chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -0,0 +1,104 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotCreateAppointmentParams,
HubSpotCreateAppointmentResponse,
} from '@/tools/hubspot/types'
import { APPOINTMENT_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotCreateAppointment')
export const hubspotCreateAppointmentTool: ToolConfig<
HubSpotCreateAppointmentParams,
HubSpotCreateAppointmentResponse
> = {
id: 'hubspot_create_appointment',
name: 'Create Appointment in HubSpot',
description: 'Create a new appointment in HubSpot',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
properties: {
type: 'object',
required: true,
visibility: 'user-or-llm',
description:
'Appointment properties as JSON object (e.g., {"hs_appointment_name": "Discovery Call", "hs_appointment_start": "2024-01-15T10:00:00Z", "hs_appointment_end": "2024-01-15T11:00:00Z"})',
},
associations: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of associations to create with the appointment as JSON. Each object should have "to.id" and "types" array with "associationCategory" and "associationTypeId"',
},
},
request: {
url: () => 'https://api.hubapi.com/crm/v3/objects/appointments',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
let properties = params.properties
if (typeof properties === 'string') {
try {
properties = JSON.parse(properties)
} catch (e) {
throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.')
}
}
const body: Record<string, unknown> = { properties }
let associations = params.associations
if (typeof associations === 'string') {
try {
associations = JSON.parse(associations)
} catch (e) {
throw new Error(
'Invalid JSON format for associations. Please provide a valid JSON array.'
)
}
}
if (Array.isArray(associations) && associations.length > 0) {
body.associations = associations
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to create appointment in HubSpot')
}
return {
success: true,
output: { appointment: data, appointmentId: data.id, success: true },
}
},
outputs: {
appointment: APPOINTMENT_OBJECT_OUTPUT,
appointmentId: { type: 'string', description: 'The created appointment ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
@@ -0,0 +1,140 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotCreateAssociationParams,
HubSpotCreateAssociationResponse,
} from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotCreateAssociation')
export const hubspotCreateAssociationTool: ToolConfig<
HubSpotCreateAssociationParams,
HubSpotCreateAssociationResponse
> = {
id: 'hubspot_create_association',
name: 'Create Association in HubSpot',
description:
'Associate two HubSpot records. Creates the default (unlabeled) association unless an association type ID is provided',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
objectType: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Source object type (e.g., "emails", "notes", "contacts")',
},
objectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'ID of the source record',
},
toObjectType: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Target object type to associate to (e.g., "contacts", "companies", "deals")',
},
toObjectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'ID of the target record',
},
associationCategory: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Association category for a labeled association (HUBSPOT_DEFINED, USER_DEFINED, INTEGRATOR_DEFINED). Defaults to HUBSPOT_DEFINED when an association type ID is provided',
},
associationTypeId: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description:
'Specific association type ID for a labeled association. Omit to create the default association for the object pair',
},
},
request: {
url: (params) => {
const from = `${encodeURIComponent(params.objectType.trim())}/${encodeURIComponent(params.objectId.trim())}`
const to = `${encodeURIComponent(params.toObjectType.trim())}/${encodeURIComponent(params.toObjectId.trim())}`
return params.associationTypeId != null
? `https://api.hubapi.com/crm/v4/objects/${from}/associations/${to}`
: `https://api.hubapi.com/crm/v4/objects/${from}/associations/default/${to}`
},
method: 'PUT',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
const headers: Record<string, string> = {
Authorization: `Bearer ${params.accessToken}`,
}
if (params.associationTypeId != null) {
headers['Content-Type'] = 'application/json'
}
return headers
},
body: (params) => {
if (params.associationTypeId == null) {
return undefined
}
return [
{
associationCategory: params.associationCategory || 'HUBSPOT_DEFINED',
associationTypeId: params.associationTypeId,
},
]
},
},
transformResponse: async (response: Response, params) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to create association in HubSpot')
}
const batchResult = Array.isArray(data.results) ? data.results[0] : undefined
return {
success: true,
output: {
fromObjectId: data.fromObjectId ?? batchResult?.from?.id ?? params?.objectId ?? '',
toObjectId: data.toObjectId ?? batchResult?.to?.id ?? params?.toObjectId ?? '',
labels: data.labels ?? [],
success: true,
},
}
},
outputs: {
fromObjectId: { type: 'string', description: 'ID of the source record' },
toObjectId: { type: 'string', description: 'ID of the associated target record' },
labels: {
type: 'array',
description: 'Association labels (empty for default associations)',
items: { type: 'string', description: 'Association label' },
},
success: { type: 'boolean', description: 'Operation success status' },
},
}
+116
View File
@@ -0,0 +1,116 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotCreateCompanyParams,
HubSpotCreateCompanyResponse,
} from '@/tools/hubspot/types'
import { COMPANY_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotCreateCompany')
export const hubspotCreateCompanyTool: ToolConfig<
HubSpotCreateCompanyParams,
HubSpotCreateCompanyResponse
> = {
id: 'hubspot_create_company',
name: 'Create Company in HubSpot',
description: 'Create a new company in HubSpot',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
properties: {
type: 'object',
required: true,
visibility: 'user-or-llm',
description:
'Company properties as JSON object (e.g., {"name": "Acme Inc", "domain": "acme.com", "industry": "Technology"})',
},
associations: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of associations to create with the company as JSON (each with "to.id" and "types" containing "associationCategory" and "associationTypeId")',
},
},
request: {
url: () => 'https://api.hubapi.com/crm/v3/objects/companies',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
let properties = params.properties
if (typeof properties === 'string') {
try {
properties = JSON.parse(properties)
} catch (e) {
throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.')
}
}
const body: any = {
properties,
}
let associations = params.associations
if (typeof associations === 'string') {
try {
associations = JSON.parse(associations)
} catch (e) {
throw new Error(
'Invalid JSON format for associations. Please provide a valid JSON array.'
)
}
}
if (Array.isArray(associations) && associations.length > 0) {
body.associations = associations
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to create company in HubSpot')
}
return {
success: true,
output: {
company: data,
companyId: data.id,
success: true,
},
}
},
outputs: {
company: COMPANY_OBJECT_OUTPUT,
companyId: { type: 'string', description: 'The created company ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+117
View File
@@ -0,0 +1,117 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotCreateContactParams,
HubSpotCreateContactResponse,
} from '@/tools/hubspot/types'
import { CONTACT_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotCreateContact')
export const hubspotCreateContactTool: ToolConfig<
HubSpotCreateContactParams,
HubSpotCreateContactResponse
> = {
id: 'hubspot_create_contact',
name: 'Create Contact in HubSpot',
description:
'Create a new contact in HubSpot. Requires at least one of: email, firstname, or lastname',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
properties: {
type: 'object',
required: true,
visibility: 'user-or-llm',
description:
'Contact properties as JSON object. Must include at least one of: email, firstname, or lastname (e.g., {"email": "john@example.com", "firstname": "John", "lastname": "Doe"})',
},
associations: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of associations to create with the contact as JSON. Each object should have "to.id" (company/deal ID) and "types" array with "associationCategory" and "associationTypeId"',
},
},
request: {
url: () => 'https://api.hubapi.com/crm/v3/objects/contacts',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
let properties = params.properties
if (typeof properties === 'string') {
try {
properties = JSON.parse(properties)
} catch (e) {
throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.')
}
}
const body: any = {
properties,
}
let associations = params.associations
if (typeof associations === 'string') {
try {
associations = JSON.parse(associations)
} catch (e) {
throw new Error(
'Invalid JSON format for associations. Please provide a valid JSON array.'
)
}
}
if (Array.isArray(associations) && associations.length > 0) {
body.associations = associations
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to create contact in HubSpot')
}
return {
success: true,
output: {
contact: data,
contactId: data.id,
success: true,
},
}
},
outputs: {
contact: CONTACT_OBJECT_OUTPUT,
contactId: { type: 'string', description: 'The created contact ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+102
View File
@@ -0,0 +1,102 @@
import { createLogger } from '@sim/logger'
import type { HubSpotCreateDealParams, HubSpotCreateDealResponse } from '@/tools/hubspot/types'
import { DEAL_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotCreateDeal')
export const hubspotCreateDealTool: ToolConfig<HubSpotCreateDealParams, HubSpotCreateDealResponse> =
{
id: 'hubspot_create_deal',
name: 'Create Deal in HubSpot',
description:
'Create a new deal in HubSpot with the given properties (e.g., dealname, amount, dealstage)',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
properties: {
type: 'object',
required: true,
visibility: 'user-or-llm',
description:
'Deal properties as JSON object. Must include dealname (e.g., {"dealname": "New Deal", "amount": "5000", "dealstage": "appointmentscheduled"})',
},
associations: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of associations to create with the deal as JSON. Each object should have "to.id" and "types" array with "associationCategory" and "associationTypeId"',
},
},
request: {
url: () => 'https://api.hubapi.com/crm/v3/objects/deals',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
let properties = params.properties
if (typeof properties === 'string') {
try {
properties = JSON.parse(properties)
} catch (e) {
throw new Error(
'Invalid JSON format for properties. Please provide a valid JSON object.'
)
}
}
const body: Record<string, unknown> = { properties }
let associations = params.associations
if (typeof associations === 'string') {
try {
associations = JSON.parse(associations)
} catch (e) {
throw new Error(
'Invalid JSON format for associations. Please provide a valid JSON array.'
)
}
}
if (Array.isArray(associations) && associations.length > 0) {
body.associations = associations
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to create deal in HubSpot')
}
return {
success: true,
output: { deal: data, dealId: data.id, success: true },
}
},
outputs: {
deal: DEAL_OBJECT_OUTPUT,
dealId: { type: 'string', description: 'The created deal ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+114
View File
@@ -0,0 +1,114 @@
import { createLogger } from '@sim/logger'
import type { HubSpotCreateEmailParams, HubSpotCreateEmailResponse } from '@/tools/hubspot/types'
import { EMAIL_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotCreateEmail')
export const hubspotCreateEmailTool: ToolConfig<
HubSpotCreateEmailParams,
HubSpotCreateEmailResponse
> = {
id: 'hubspot_create_email',
name: 'Create Email in HubSpot',
description:
'Log an email engagement in HubSpot and optionally associate it with contacts. Requires the hs_timestamp property',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
properties: {
type: 'object',
required: true,
visibility: 'user-or-llm',
description:
'Email properties as JSON object. Must include "hs_timestamp" (ISO 8601). Common fields: "hs_email_direction" (EMAIL, INCOMING_EMAIL, FORWARDED_EMAIL), "hs_email_status" (SENT, SENDING, SCHEDULED, FAILED, BOUNCED), "hs_email_subject", "hs_email_text", "hs_email_html", "hs_email_headers" (JSON string)',
},
associations: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of associations as JSON. Each object has "to.id" (record ID) and "types" array with "associationCategory" ("HUBSPOT_DEFINED") and "associationTypeId" (198 = email→contact)',
},
},
request: {
url: () => 'https://api.hubapi.com/crm/v3/objects/emails',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
let properties = params.properties
if (typeof properties === 'string') {
try {
properties = JSON.parse(properties)
} catch (e) {
throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.')
}
}
const body: Record<string, unknown> = {
properties,
}
let associations = params.associations
if (typeof associations === 'string') {
try {
associations = JSON.parse(associations)
} catch (e) {
throw new Error(
'Invalid JSON format for associations. Please provide a valid JSON array.'
)
}
}
if (Array.isArray(associations) && associations.length > 0) {
body.associations = associations
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to create email in HubSpot')
}
return {
success: true,
output: {
email: data,
emailId: data.id,
success: true,
},
}
},
outputs: {
email: EMAIL_OBJECT_OUTPUT,
emailId: { type: 'string', description: 'The created email engagement ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+104
View File
@@ -0,0 +1,104 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotCreateLineItemParams,
HubSpotCreateLineItemResponse,
} from '@/tools/hubspot/types'
import { LINE_ITEM_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotCreateLineItem')
export const hubspotCreateLineItemTool: ToolConfig<
HubSpotCreateLineItemParams,
HubSpotCreateLineItemResponse
> = {
id: 'hubspot_create_line_item',
name: 'Create Line Item in HubSpot',
description: 'Create a new line item in HubSpot. Requires at least a name property',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
properties: {
type: 'object',
required: true,
visibility: 'user-or-llm',
description:
'Line item properties as JSON object (e.g., {"name": "Product A", "quantity": "2", "price": "50.00", "hs_sku": "SKU-001"})',
},
associations: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of associations to create with the line item as JSON. Each object should have "to.id" and "types" array with "associationCategory" and "associationTypeId"',
},
},
request: {
url: () => 'https://api.hubapi.com/crm/v3/objects/line_items',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
let properties = params.properties
if (typeof properties === 'string') {
try {
properties = JSON.parse(properties)
} catch (e) {
throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.')
}
}
const body: Record<string, unknown> = { properties }
let associations = params.associations
if (typeof associations === 'string') {
try {
associations = JSON.parse(associations)
} catch (e) {
throw new Error(
'Invalid JSON format for associations. Please provide a valid JSON array.'
)
}
}
if (Array.isArray(associations) && associations.length > 0) {
body.associations = associations
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to create line item in HubSpot')
}
return {
success: true,
output: { lineItem: data, lineItemId: data.id, success: true },
}
},
outputs: {
lineItem: LINE_ITEM_OBJECT_OUTPUT,
lineItemId: { type: 'string', description: 'The created line item ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+92
View File
@@ -0,0 +1,92 @@
import { createLogger } from '@sim/logger'
import type { HubSpotCreateListParams, HubSpotCreateListResponse } from '@/tools/hubspot/types'
import { LIST_OUTPUT_PROPERTIES } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotCreateList')
export const hubspotCreateListTool: ToolConfig<HubSpotCreateListParams, HubSpotCreateListResponse> =
{
id: 'hubspot_create_list',
name: 'Create List in HubSpot',
description:
'Create a new list in HubSpot. Specify the object type and processing type (MANUAL or DYNAMIC)',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
name: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Name of the list',
},
objectTypeId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Object type ID (e.g., "0-1" for contacts, "0-2" for companies)',
},
processingType: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Processing type: "MANUAL" for static lists or "DYNAMIC" for active lists',
},
},
request: {
url: () => 'https://api.hubapi.com/crm/v3/lists',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => ({
name: params.name,
objectTypeId: params.objectTypeId,
processingType: params.processingType,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to create list in HubSpot')
}
return {
success: true,
output: {
list: data.list ?? data,
listId: data.list?.listId ?? data.listId ?? data.id,
success: true,
},
}
},
outputs: {
list: {
type: 'object',
description: 'HubSpot list',
properties: LIST_OUTPUT_PROPERTIES,
},
listId: { type: 'string', description: 'The created list ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+114
View File
@@ -0,0 +1,114 @@
import { createLogger } from '@sim/logger'
import type { HubSpotCreateNoteParams, HubSpotCreateNoteResponse } from '@/tools/hubspot/types'
import { NOTE_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotCreateNote')
export const hubspotCreateNoteTool: ToolConfig<HubSpotCreateNoteParams, HubSpotCreateNoteResponse> =
{
id: 'hubspot_create_note',
name: 'Create Note in HubSpot',
description:
'Log a note in HubSpot and optionally associate it with contacts, companies, or deals. Requires hs_timestamp and hs_note_body properties',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
properties: {
type: 'object',
required: true,
visibility: 'user-or-llm',
description:
'Note properties as JSON object. Must include "hs_timestamp" (ISO 8601 activity time) and "hs_note_body" (the note text). e.g., {"hs_timestamp": "2026-06-13T00:00:00Z", "hs_note_body": "Followed up via phone"}',
},
associations: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of associations as JSON. Each object has "to.id" (record ID) and "types" array with "associationCategory" ("HUBSPOT_DEFINED") and "associationTypeId" (202 = note→contact, 190 = note→company, 214 = note→deal)',
},
},
request: {
url: () => 'https://api.hubapi.com/crm/v3/objects/notes',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
let properties = params.properties
if (typeof properties === 'string') {
try {
properties = JSON.parse(properties)
} catch (e) {
throw new Error(
'Invalid JSON format for properties. Please provide a valid JSON object.'
)
}
}
const body: Record<string, unknown> = {
properties,
}
let associations = params.associations
if (typeof associations === 'string') {
try {
associations = JSON.parse(associations)
} catch (e) {
throw new Error(
'Invalid JSON format for associations. Please provide a valid JSON array.'
)
}
}
if (Array.isArray(associations) && associations.length > 0) {
body.associations = associations
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to create note in HubSpot')
}
return {
success: true,
output: {
note: data,
noteId: data.id,
success: true,
},
}
},
outputs: {
note: NOTE_OBJECT_OUTPUT,
noteId: { type: 'string', description: 'The created note ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+101
View File
@@ -0,0 +1,101 @@
import { createLogger } from '@sim/logger'
import type { HubSpotCreateTicketParams, HubSpotCreateTicketResponse } from '@/tools/hubspot/types'
import { TICKET_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotCreateTicket')
export const hubspotCreateTicketTool: ToolConfig<
HubSpotCreateTicketParams,
HubSpotCreateTicketResponse
> = {
id: 'hubspot_create_ticket',
name: 'Create Ticket in HubSpot',
description: 'Create a new ticket in HubSpot. Requires subject and hs_pipeline_stage properties',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
properties: {
type: 'object',
required: true,
visibility: 'user-or-llm',
description:
'Ticket properties as JSON object. Must include subject and hs_pipeline_stage (e.g., {"subject": "Support request", "hs_pipeline_stage": "1", "hs_ticket_priority": "HIGH"})',
},
associations: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of associations to create with the ticket as JSON. Each object should have "to.id" and "types" array with "associationCategory" and "associationTypeId"',
},
},
request: {
url: () => 'https://api.hubapi.com/crm/v3/objects/tickets',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
let properties = params.properties
if (typeof properties === 'string') {
try {
properties = JSON.parse(properties)
} catch (e) {
throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.')
}
}
const body: Record<string, unknown> = { properties }
let associations = params.associations
if (typeof associations === 'string') {
try {
associations = JSON.parse(associations)
} catch (e) {
throw new Error(
'Invalid JSON format for associations. Please provide a valid JSON array.'
)
}
}
if (Array.isArray(associations) && associations.length > 0) {
body.associations = associations
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to create ticket in HubSpot')
}
return {
success: true,
output: { ticket: data, ticketId: data.id, success: true },
}
},
outputs: {
ticket: TICKET_OBJECT_OUTPUT,
ticketId: { type: 'string', description: 'The created ticket ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+99
View File
@@ -0,0 +1,99 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotGetAppointmentParams,
HubSpotGetAppointmentResponse,
} from '@/tools/hubspot/types'
import { APPOINTMENT_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotGetAppointment')
export const hubspotGetAppointmentTool: ToolConfig<
HubSpotGetAppointmentParams,
HubSpotGetAppointmentResponse
> = {
id: 'hubspot_get_appointment',
name: 'Get Appointment from HubSpot',
description: 'Retrieve a single appointment by ID from HubSpot',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
appointmentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The HubSpot appointment ID to retrieve',
},
idProperty: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Property to use as unique identifier. If not specified, uses record ID',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot property names to return (e.g., "hs_appointment_name,hs_appointment_start")',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of object types to retrieve associated IDs for (e.g., "contacts,companies")',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.hubapi.com/crm/v3/objects/appointments/${params.appointmentId.trim()}`
const queryParams = new URLSearchParams()
if (params.idProperty) queryParams.append('idProperty', params.idProperty)
if (params.properties) queryParams.append('properties', params.properties)
if (params.associations) queryParams.append('associations', params.associations)
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to get appointment from HubSpot')
}
return {
success: true,
output: { appointment: data, appointmentId: data.id, success: true },
}
},
outputs: {
appointment: APPOINTMENT_OBJECT_OUTPUT,
appointmentId: { type: 'string', description: 'The retrieved appointment ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+84
View File
@@ -0,0 +1,84 @@
import { createLogger } from '@sim/logger'
import type { HubSpotGetCartParams, HubSpotGetCartResponse } from '@/tools/hubspot/types'
import { GENERIC_CRM_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotGetCart')
export const hubspotGetCartTool: ToolConfig<HubSpotGetCartParams, HubSpotGetCartResponse> = {
id: 'hubspot_get_cart',
name: 'Get Cart from HubSpot',
description: 'Retrieve a single cart by ID from HubSpot',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
cartId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The HubSpot cart ID to retrieve',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of HubSpot property names to return',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of object types to retrieve associated IDs for',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.hubapi.com/crm/v3/objects/carts/${params.cartId.trim()}`
const queryParams = new URLSearchParams()
if (params.properties) queryParams.append('properties', params.properties)
if (params.associations) queryParams.append('associations', params.associations)
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to get cart from HubSpot')
}
return {
success: true,
output: { cart: data, cartId: data.id, success: true },
}
},
outputs: {
cart: GENERIC_CRM_OBJECT_OUTPUT,
cartId: { type: 'string', description: 'The retrieved cart ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+110
View File
@@ -0,0 +1,110 @@
import { createLogger } from '@sim/logger'
import type { HubSpotGetCompanyParams, HubSpotGetCompanyResponse } from '@/tools/hubspot/types'
import { COMPANY_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotGetCompany')
export const hubspotGetCompanyTool: ToolConfig<HubSpotGetCompanyParams, HubSpotGetCompanyResponse> =
{
id: 'hubspot_get_company',
name: 'Get Company from HubSpot',
description: 'Retrieve a single company by ID or domain from HubSpot',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
companyId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The HubSpot company ID (numeric string) or domain to retrieve',
},
idProperty: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Property to use as unique identifier (e.g., "domain"). If not specified, uses record ID',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot property names to return (e.g., "name,domain,industry")',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of object types to retrieve associated IDs for (e.g., "contacts,deals")',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.hubapi.com/crm/v3/objects/companies/${params.companyId.trim()}`
const queryParams = new URLSearchParams()
if (params.idProperty) {
queryParams.append('idProperty', params.idProperty)
}
if (params.properties) {
queryParams.append('properties', params.properties)
}
if (params.associations) {
queryParams.append('associations', params.associations)
}
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to get company from HubSpot')
}
return {
success: true,
output: {
company: data,
companyId: data.id,
success: true,
},
}
},
outputs: {
company: COMPANY_OBJECT_OUTPUT,
companyId: { type: 'string', description: 'The retrieved company ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+110
View File
@@ -0,0 +1,110 @@
import { createLogger } from '@sim/logger'
import type { HubSpotGetContactParams, HubSpotGetContactResponse } from '@/tools/hubspot/types'
import { CONTACT_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotGetContact')
export const hubspotGetContactTool: ToolConfig<HubSpotGetContactParams, HubSpotGetContactResponse> =
{
id: 'hubspot_get_contact',
name: 'Get Contact from HubSpot',
description: 'Retrieve a single contact by ID or email from HubSpot',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
contactId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The HubSpot contact ID (numeric string) or email address to retrieve',
},
idProperty: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Property to use as unique identifier (e.g., "email"). If not specified, uses record ID',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot property names to return (e.g., "email,firstname,lastname,phone")',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of object types to retrieve associated IDs for (e.g., "companies,deals")',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.hubapi.com/crm/v3/objects/contacts/${params.contactId.trim()}`
const queryParams = new URLSearchParams()
if (params.idProperty) {
queryParams.append('idProperty', params.idProperty)
}
if (params.properties) {
queryParams.append('properties', params.properties)
}
if (params.associations) {
queryParams.append('associations', params.associations)
}
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to get contact from HubSpot')
}
return {
success: true,
output: {
contact: data,
contactId: data.id,
success: true,
},
}
},
outputs: {
contact: CONTACT_OBJECT_OUTPUT,
contactId: { type: 'string', description: 'The retrieved contact ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+93
View File
@@ -0,0 +1,93 @@
import { createLogger } from '@sim/logger'
import type { HubSpotGetDealParams, HubSpotGetDealResponse } from '@/tools/hubspot/types'
import { DEAL_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotGetDeal')
export const hubspotGetDealTool: ToolConfig<HubSpotGetDealParams, HubSpotGetDealResponse> = {
id: 'hubspot_get_deal',
name: 'Get Deal from HubSpot',
description: 'Retrieve a single deal by ID from HubSpot',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
dealId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The HubSpot deal ID to retrieve',
},
idProperty: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Property to use as unique identifier. If not specified, uses record ID',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot property names to return (e.g., "dealname,amount,dealstage")',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of object types to retrieve associated IDs for (e.g., "contacts,companies")',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.hubapi.com/crm/v3/objects/deals/${params.dealId.trim()}`
const queryParams = new URLSearchParams()
if (params.idProperty) queryParams.append('idProperty', params.idProperty)
if (params.properties) queryParams.append('properties', params.properties)
if (params.associations) queryParams.append('associations', params.associations)
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to get deal from HubSpot')
}
return {
success: true,
output: { deal: data, dealId: data.id, success: true },
}
},
outputs: {
deal: DEAL_OBJECT_OUTPUT,
dealId: { type: 'string', description: 'The retrieved deal ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+100
View File
@@ -0,0 +1,100 @@
import { createLogger } from '@sim/logger'
import type { HubSpotGetEmailParams, HubSpotGetEmailResponse } from '@/tools/hubspot/types'
import { EMAIL_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotGetEmail')
export const hubspotGetEmailTool: ToolConfig<HubSpotGetEmailParams, HubSpotGetEmailResponse> = {
id: 'hubspot_get_email',
name: 'Get Email from HubSpot',
description:
'Retrieve a single email engagement by ID from HubSpot (content requires the sales-email-read scope)',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
emailId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The HubSpot email engagement ID to retrieve',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot property names to return (e.g., "hs_email_subject,hs_email_text,hs_timestamp")',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of object types to retrieve associated IDs for (e.g., "contacts,companies,deals")',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.hubapi.com/crm/v3/objects/emails/${params.emailId.trim()}`
const queryParams = new URLSearchParams()
if (params.properties) {
queryParams.append('properties', params.properties)
}
if (params.associations) {
queryParams.append('associations', params.associations)
}
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to get email from HubSpot')
}
return {
success: true,
output: {
email: data,
emailId: data.id,
success: true,
},
}
},
outputs: {
email: EMAIL_OBJECT_OUTPUT,
emailId: { type: 'string', description: 'The retrieved email engagement ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+96
View File
@@ -0,0 +1,96 @@
import { createLogger } from '@sim/logger'
import type { HubSpotGetLineItemParams, HubSpotGetLineItemResponse } from '@/tools/hubspot/types'
import { LINE_ITEM_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotGetLineItem')
export const hubspotGetLineItemTool: ToolConfig<
HubSpotGetLineItemParams,
HubSpotGetLineItemResponse
> = {
id: 'hubspot_get_line_item',
name: 'Get Line Item from HubSpot',
description: 'Retrieve a single line item by ID from HubSpot',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
lineItemId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The HubSpot line item ID to retrieve',
},
idProperty: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Property to use as unique identifier. If not specified, uses record ID',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot property names to return (e.g., "name,quantity,price,amount")',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of object types to retrieve associated IDs for (e.g., "deals,quotes")',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.hubapi.com/crm/v3/objects/line_items/${params.lineItemId.trim()}`
const queryParams = new URLSearchParams()
if (params.idProperty) queryParams.append('idProperty', params.idProperty)
if (params.properties) queryParams.append('properties', params.properties)
if (params.associations) queryParams.append('associations', params.associations)
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to get line item from HubSpot')
}
return {
success: true,
output: { lineItem: data, lineItemId: data.id, success: true },
}
},
outputs: {
lineItem: LINE_ITEM_OBJECT_OUTPUT,
lineItemId: { type: 'string', description: 'The retrieved line item ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+73
View File
@@ -0,0 +1,73 @@
import { createLogger } from '@sim/logger'
import type { HubSpotGetListParams, HubSpotGetListResponse } from '@/tools/hubspot/types'
import { LIST_OUTPUT_PROPERTIES } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotGetList')
export const hubspotGetListTool: ToolConfig<HubSpotGetListParams, HubSpotGetListResponse> = {
id: 'hubspot_get_list',
name: 'Get List from HubSpot',
description: 'Retrieve a single list by ID from HubSpot',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
listId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The HubSpot list ID to retrieve',
},
},
request: {
url: (params) => `https://api.hubapi.com/crm/v3/lists/${params.listId.trim()}`,
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to get list from HubSpot')
}
return {
success: true,
output: {
list: data.list ?? data,
listId: data.list?.listId ?? data.listId ?? data.id,
success: true,
},
}
},
outputs: {
list: {
type: 'object',
description: 'HubSpot list',
properties: LIST_OUTPUT_PROPERTIES,
},
listId: { type: 'string', description: 'The retrieved list ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
@@ -0,0 +1,76 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotGetMarketingEventParams,
HubSpotGetMarketingEventResponse,
} from '@/tools/hubspot/types'
import { MARKETING_EVENT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotGetMarketingEvent')
export const hubspotGetMarketingEventTool: ToolConfig<
HubSpotGetMarketingEventParams,
HubSpotGetMarketingEventResponse
> = {
id: 'hubspot_get_marketing_event',
name: 'Get Marketing Event from HubSpot',
description: 'Retrieve a single marketing event by ID from HubSpot',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
eventId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The HubSpot marketing event objectId to retrieve',
},
},
request: {
url: (params) =>
`https://api.hubapi.com/marketing/v3/marketing-events/${params.eventId.trim()}`,
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to get marketing event from HubSpot')
}
return {
success: true,
output: {
event: data,
eventId: data.objectId ?? data.id,
success: true,
},
}
},
outputs: {
event: MARKETING_EVENT_OUTPUT,
eventId: { type: 'string', description: 'The retrieved marketing event ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+99
View File
@@ -0,0 +1,99 @@
import { createLogger } from '@sim/logger'
import type { HubSpotGetNoteParams, HubSpotGetNoteResponse } from '@/tools/hubspot/types'
import { NOTE_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotGetNote')
export const hubspotGetNoteTool: ToolConfig<HubSpotGetNoteParams, HubSpotGetNoteResponse> = {
id: 'hubspot_get_note',
name: 'Get Note from HubSpot',
description: 'Retrieve a single note by ID from HubSpot',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
noteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The HubSpot note ID to retrieve',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot property names to return (e.g., "hs_note_body,hs_timestamp,hubspot_owner_id")',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of object types to retrieve associated IDs for (e.g., "contacts,companies,deals")',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.hubapi.com/crm/v3/objects/notes/${params.noteId.trim()}`
const queryParams = new URLSearchParams()
if (params.properties) {
queryParams.append('properties', params.properties)
}
if (params.associations) {
queryParams.append('associations', params.associations)
}
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to get note from HubSpot')
}
return {
success: true,
output: {
note: data,
noteId: data.id,
success: true,
},
}
},
outputs: {
note: NOTE_OBJECT_OUTPUT,
noteId: { type: 'string', description: 'The retrieved note ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+118
View File
@@ -0,0 +1,118 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotGetPropertiesParams,
HubSpotGetPropertiesResponse,
} from '@/tools/hubspot/types'
import { PROPERTIES_ARRAY_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotGetProperties')
export const hubspotGetPropertiesTool: ToolConfig<
HubSpotGetPropertiesParams,
HubSpotGetPropertiesResponse
> = {
id: 'hubspot_get_properties',
name: 'Get Properties from HubSpot',
description:
'Read property definitions and their enumeration (picklist) options for a HubSpot object type, e.g. the values for lifecyclestage or hs_lead_status on contacts',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
objectType: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Object type to read properties for (e.g., "contacts", "companies", "deals", "tickets", "line_items", "quotes")',
},
propertyName: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Internal name of a single property to retrieve (e.g., "hs_lead_status"). Omit to return all properties for the object type',
},
archived: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether to return only archived properties (default false)',
},
},
request: {
url: (params) => {
const objectType = params.objectType.trim()
const baseUrl = params.propertyName
? `https://api.hubapi.com/crm/v3/properties/${encodeURIComponent(objectType)}/${encodeURIComponent(params.propertyName.trim())}`
: `https://api.hubapi.com/crm/v3/properties/${encodeURIComponent(objectType)}`
const queryParams = new URLSearchParams()
if (params.archived !== undefined) {
queryParams.append('archived', String(params.archived))
}
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response, params) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to get properties from HubSpot')
}
const properties = Array.isArray(data.results) ? data.results : [data]
return {
success: true,
output: {
properties,
metadata: {
totalReturned: properties.length,
objectType: params?.objectType ?? '',
},
success: true,
},
}
},
outputs: {
properties: PROPERTIES_ARRAY_OUTPUT,
metadata: {
type: 'object',
description: 'Response metadata',
properties: {
totalReturned: { type: 'number', description: 'Number of property definitions returned' },
objectType: { type: 'string', description: 'Object type the properties belong to' },
},
},
success: { type: 'boolean', description: 'Operation success status' },
},
}
+93
View File
@@ -0,0 +1,93 @@
import { createLogger } from '@sim/logger'
import type { HubSpotGetQuoteParams, HubSpotGetQuoteResponse } from '@/tools/hubspot/types'
import { QUOTE_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotGetQuote')
export const hubspotGetQuoteTool: ToolConfig<HubSpotGetQuoteParams, HubSpotGetQuoteResponse> = {
id: 'hubspot_get_quote',
name: 'Get Quote from HubSpot',
description: 'Retrieve a single quote by ID from HubSpot',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
quoteId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The HubSpot quote ID to retrieve',
},
idProperty: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Property to use as unique identifier. If not specified, uses record ID',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot property names to return (e.g., "hs_title,hs_expiration_date,hs_status")',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of object types to retrieve associated IDs for (e.g., "deals,line_items")',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.hubapi.com/crm/v3/objects/quotes/${params.quoteId.trim()}`
const queryParams = new URLSearchParams()
if (params.idProperty) queryParams.append('idProperty', params.idProperty)
if (params.properties) queryParams.append('properties', params.properties)
if (params.associations) queryParams.append('associations', params.associations)
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to get quote from HubSpot')
}
return {
success: true,
output: { quote: data, quoteId: data.id, success: true },
}
},
outputs: {
quote: QUOTE_OBJECT_OUTPUT,
quoteId: { type: 'string', description: 'The retrieved quote ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+93
View File
@@ -0,0 +1,93 @@
import { createLogger } from '@sim/logger'
import type { HubSpotGetTicketParams, HubSpotGetTicketResponse } from '@/tools/hubspot/types'
import { TICKET_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotGetTicket')
export const hubspotGetTicketTool: ToolConfig<HubSpotGetTicketParams, HubSpotGetTicketResponse> = {
id: 'hubspot_get_ticket',
name: 'Get Ticket from HubSpot',
description: 'Retrieve a single ticket by ID from HubSpot',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
ticketId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The HubSpot ticket ID to retrieve',
},
idProperty: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Property to use as unique identifier. If not specified, uses record ID',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot property names to return (e.g., "subject,content,hs_ticket_priority")',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of object types to retrieve associated IDs for (e.g., "contacts,companies")',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.hubapi.com/crm/v3/objects/tickets/${params.ticketId.trim()}`
const queryParams = new URLSearchParams()
if (params.idProperty) queryParams.append('idProperty', params.idProperty)
if (params.properties) queryParams.append('properties', params.properties)
if (params.associations) queryParams.append('associations', params.associations)
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to get ticket from HubSpot')
}
return {
success: true,
output: { ticket: data, ticketId: data.id, success: true },
}
},
outputs: {
ticket: TICKET_OBJECT_OUTPUT,
ticketId: { type: 'string', description: 'The retrieved ticket ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+105
View File
@@ -0,0 +1,105 @@
import { createLogger } from '@sim/logger'
import type { HubSpotGetUsersParams, HubSpotGetUsersResponse } from '@/tools/hubspot/types'
import { GENERIC_CRM_ARRAY_OUTPUT, PAGING_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotGetUsers')
export const hubspotGetUsersTool: ToolConfig<HubSpotGetUsersParams, HubSpotGetUsersResponse> = {
id: 'hubspot_get_users',
name: 'Get Users from HubSpot',
description: 'Retrieve all users from HubSpot account',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
limit: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Number of results to return (default: 10, max: 100)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page of results (from previous response)',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot user property names to return (e.g., "hs_email,hs_given_name,hs_family_name")',
},
},
request: {
url: (params) => {
const baseUrl = 'https://api.hubapi.com/crm/v3/objects/users'
const queryParams = new URLSearchParams()
if (params.limit) {
queryParams.append('limit', params.limit)
}
if (params.after) {
queryParams.append('after', params.after)
}
if (params.properties) {
queryParams.append('properties', params.properties)
}
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to fetch users from HubSpot')
}
const users = data.results || []
return {
success: true,
output: {
users,
paging: data.paging ?? null,
totalItems: users.length,
success: true,
},
}
},
outputs: {
users: GENERIC_CRM_ARRAY_OUTPUT,
paging: PAGING_OUTPUT,
totalItems: { type: 'number', description: 'Total number of users returned' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+50
View File
@@ -0,0 +1,50 @@
export { hubspotCreateAppointmentTool } from './create_appointment'
export { hubspotCreateAssociationTool } from './create_association'
export { hubspotCreateCompanyTool } from './create_company'
export { hubspotCreateContactTool } from './create_contact'
export { hubspotCreateDealTool } from './create_deal'
export { hubspotCreateEmailTool } from './create_email'
export { hubspotCreateLineItemTool } from './create_line_item'
export { hubspotCreateListTool } from './create_list'
export { hubspotCreateNoteTool } from './create_note'
export { hubspotCreateTicketTool } from './create_ticket'
export { hubspotGetAppointmentTool } from './get_appointment'
export { hubspotGetCartTool } from './get_cart'
export { hubspotGetCompanyTool } from './get_company'
export { hubspotGetContactTool } from './get_contact'
export { hubspotGetDealTool } from './get_deal'
export { hubspotGetEmailTool } from './get_email'
export { hubspotGetLineItemTool } from './get_line_item'
export { hubspotGetListTool } from './get_list'
export { hubspotGetMarketingEventTool } from './get_marketing_event'
export { hubspotGetNoteTool } from './get_note'
export { hubspotGetPropertiesTool } from './get_properties'
export { hubspotGetQuoteTool } from './get_quote'
export { hubspotGetTicketTool } from './get_ticket'
export { hubspotGetUsersTool } from './get_users'
export { hubspotListAppointmentsTool } from './list_appointments'
export { hubspotListAssociationsTool } from './list_associations'
export { hubspotListCartsTool } from './list_carts'
export { hubspotListCompaniesTool } from './list_companies'
export { hubspotListContactsTool } from './list_contacts'
export { hubspotListDealsTool } from './list_deals'
export { hubspotListEmailsTool } from './list_emails'
export { hubspotListLineItemsTool } from './list_line_items'
export { hubspotListListsTool } from './list_lists'
export { hubspotListMarketingEventsTool } from './list_marketing_events'
export { hubspotListNotesTool } from './list_notes'
export { hubspotListOwnersTool } from './list_owners'
export { hubspotListQuotesTool } from './list_quotes'
export { hubspotListTicketsTool } from './list_tickets'
export { hubspotSearchCompaniesTool } from './search_companies'
export { hubspotSearchContactsTool } from './search_contacts'
export { hubspotSearchDealsTool } from './search_deals'
export { hubspotSearchEmailsTool } from './search_emails'
export { hubspotSearchNotesTool } from './search_notes'
export { hubspotSearchTicketsTool } from './search_tickets'
export { hubspotUpdateAppointmentTool } from './update_appointment'
export { hubspotUpdateCompanyTool } from './update_company'
export { hubspotUpdateContactTool } from './update_contact'
export { hubspotUpdateDealTool } from './update_deal'
export { hubspotUpdateLineItemTool } from './update_line_item'
export { hubspotUpdateTicketTool } from './update_ticket'
+109
View File
@@ -0,0 +1,109 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotListAppointmentsParams,
HubSpotListAppointmentsResponse,
} from '@/tools/hubspot/types'
import { APPOINTMENTS_ARRAY_OUTPUT, METADATA_OUTPUT, PAGING_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotListAppointments')
export const hubspotListAppointmentsTool: ToolConfig<
HubSpotListAppointmentsParams,
HubSpotListAppointmentsResponse
> = {
id: 'hubspot_list_appointments',
name: 'List Appointments from HubSpot',
description: 'Retrieve all appointments from HubSpot account with pagination support',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
limit: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results per page (max 100, default 10)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page of results (from previous response)',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot property names to return (e.g., "hs_appointment_name,hs_appointment_start")',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of object types to retrieve associated IDs for (e.g., "contacts,companies")',
},
},
request: {
url: (params) => {
const baseUrl = 'https://api.hubapi.com/crm/v3/objects/appointments'
const queryParams = new URLSearchParams()
if (params.limit) queryParams.append('limit', params.limit)
if (params.after) queryParams.append('after', params.after)
if (params.properties) queryParams.append('properties', params.properties)
if (params.associations) queryParams.append('associations', params.associations)
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to list appointments from HubSpot')
}
return {
success: true,
output: {
appointments: data.results || [],
paging: data.paging ?? null,
metadata: {
totalReturned: data.results?.length || 0,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
appointments: APPOINTMENTS_ARRAY_OUTPUT,
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
+121
View File
@@ -0,0 +1,121 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotListAssociationsParams,
HubSpotListAssociationsResponse,
} from '@/tools/hubspot/types'
import { ASSOCIATIONS_ARRAY_OUTPUT, METADATA_OUTPUT, PAGING_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotListAssociations')
export const hubspotListAssociationsTool: ToolConfig<
HubSpotListAssociationsParams,
HubSpotListAssociationsResponse
> = {
id: 'hubspot_list_associations',
name: 'List Associations in HubSpot',
description:
'List records of one object type associated with a given record, e.g. all emails or notes logged on a contact',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
objectType: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Source object type (e.g., "contacts", "companies", "deals")',
},
objectId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'ID of the source record',
},
toObjectType: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Target object type to list associations to (e.g., "emails", "notes", "deals")',
},
limit: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of associated records per page (default 500)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page (from previous response)',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.hubapi.com/crm/v4/objects/${encodeURIComponent(params.objectType.trim())}/${encodeURIComponent(params.objectId.trim())}/associations/${encodeURIComponent(params.toObjectType.trim())}`
const queryParams = new URLSearchParams()
if (params.limit) {
queryParams.append('limit', params.limit)
}
if (params.after) {
queryParams.append('after', params.after)
}
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to list associations from HubSpot')
}
return {
success: true,
output: {
results: data.results || [],
paging: data.paging ?? null,
metadata: {
totalReturned: data.results?.length || 0,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
results: ASSOCIATIONS_ARRAY_OUTPUT,
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
+101
View File
@@ -0,0 +1,101 @@
import { createLogger } from '@sim/logger'
import type { HubSpotListCartsParams, HubSpotListCartsResponse } from '@/tools/hubspot/types'
import { GENERIC_CRM_ARRAY_OUTPUT, METADATA_OUTPUT, PAGING_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotListCarts')
export const hubspotListCartsTool: ToolConfig<HubSpotListCartsParams, HubSpotListCartsResponse> = {
id: 'hubspot_list_carts',
name: 'List Carts from HubSpot',
description: 'Retrieve all carts from HubSpot account with pagination support',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
limit: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results per page (max 100, default 10)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page of results (from previous response)',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of HubSpot property names to return',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of object types to retrieve associated IDs for',
},
},
request: {
url: (params) => {
const baseUrl = 'https://api.hubapi.com/crm/v3/objects/carts'
const queryParams = new URLSearchParams()
if (params.limit) queryParams.append('limit', params.limit)
if (params.after) queryParams.append('after', params.after)
if (params.properties) queryParams.append('properties', params.properties)
if (params.associations) queryParams.append('associations', params.associations)
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to list carts from HubSpot')
}
return {
success: true,
output: {
carts: data.results || [],
paging: data.paging ?? null,
metadata: {
totalReturned: data.results?.length || 0,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
carts: GENERIC_CRM_ARRAY_OUTPUT,
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
+122
View File
@@ -0,0 +1,122 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotListCompaniesParams,
HubSpotListCompaniesResponse,
} from '@/tools/hubspot/types'
import { COMPANIES_ARRAY_OUTPUT, METADATA_OUTPUT, PAGING_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotListCompanies')
export const hubspotListCompaniesTool: ToolConfig<
HubSpotListCompaniesParams,
HubSpotListCompaniesResponse
> = {
id: 'hubspot_list_companies',
name: 'List Companies from HubSpot',
description: 'Retrieve all companies from HubSpot account with pagination support',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
limit: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results per page (max 100, default 10)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page of results (from previous response)',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot property names to return (e.g., "name,domain,industry")',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of object types to retrieve associated IDs for (e.g., "contacts,deals")',
},
},
request: {
url: (params) => {
const baseUrl = 'https://api.hubapi.com/crm/v3/objects/companies'
const queryParams = new URLSearchParams()
if (params.limit) {
queryParams.append('limit', params.limit)
}
if (params.after) {
queryParams.append('after', params.after)
}
if (params.properties) {
queryParams.append('properties', params.properties)
}
if (params.associations) {
queryParams.append('associations', params.associations)
}
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to list companies from HubSpot')
}
return {
success: true,
output: {
companies: data.results || [],
paging: data.paging ?? null,
metadata: {
totalReturned: data.results?.length || 0,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
companies: COMPANIES_ARRAY_OUTPUT,
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
+119
View File
@@ -0,0 +1,119 @@
import { createLogger } from '@sim/logger'
import type { HubSpotListContactsParams, HubSpotListContactsResponse } from '@/tools/hubspot/types'
import { CONTACTS_ARRAY_OUTPUT, METADATA_OUTPUT, PAGING_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotListContacts')
export const hubspotListContactsTool: ToolConfig<
HubSpotListContactsParams,
HubSpotListContactsResponse
> = {
id: 'hubspot_list_contacts',
name: 'List Contacts from HubSpot',
description: 'Retrieve all contacts from HubSpot account with pagination support',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
limit: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results per page (max 100, default 10)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page of results (from previous response)',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot property names to return (e.g., "email,firstname,lastname,phone")',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of object types to retrieve associated IDs for (e.g., "companies,deals")',
},
},
request: {
url: (params) => {
const baseUrl = 'https://api.hubapi.com/crm/v3/objects/contacts'
const queryParams = new URLSearchParams()
if (params.limit) {
queryParams.append('limit', params.limit)
}
if (params.after) {
queryParams.append('after', params.after)
}
if (params.properties) {
queryParams.append('properties', params.properties)
}
if (params.associations) {
queryParams.append('associations', params.associations)
}
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to list contacts from HubSpot')
}
return {
success: true,
output: {
contacts: data.results || [],
paging: data.paging ?? null,
metadata: {
totalReturned: data.results?.length || 0,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
contacts: CONTACTS_ARRAY_OUTPUT,
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
+116
View File
@@ -0,0 +1,116 @@
import { createLogger } from '@sim/logger'
import type { HubSpotListDealsParams, HubSpotListDealsResponse } from '@/tools/hubspot/types'
import { DEALS_ARRAY_OUTPUT, METADATA_OUTPUT, PAGING_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotListDeals')
export const hubspotListDealsTool: ToolConfig<HubSpotListDealsParams, HubSpotListDealsResponse> = {
id: 'hubspot_list_deals',
name: 'List Deals from HubSpot',
description: 'Retrieve all deals from HubSpot account with pagination support',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
limit: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results per page (max 100, default 10)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page of results (from previous response)',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot property names to return (e.g., "dealname,amount,dealstage")',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of object types to retrieve associated IDs for (e.g., "contacts,companies")',
},
},
request: {
url: (params) => {
const baseUrl = 'https://api.hubapi.com/crm/v3/objects/deals'
const queryParams = new URLSearchParams()
if (params.limit) {
queryParams.append('limit', params.limit)
}
if (params.after) {
queryParams.append('after', params.after)
}
if (params.properties) {
queryParams.append('properties', params.properties)
}
if (params.associations) {
queryParams.append('associations', params.associations)
}
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to list deals from HubSpot')
}
return {
success: true,
output: {
deals: data.results || [],
paging: data.paging ?? null,
metadata: {
totalReturned: data.results?.length || 0,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
deals: DEALS_ARRAY_OUTPUT,
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
+117
View File
@@ -0,0 +1,117 @@
import { createLogger } from '@sim/logger'
import type { HubSpotListEmailsParams, HubSpotListEmailsResponse } from '@/tools/hubspot/types'
import { EMAILS_ARRAY_OUTPUT, METADATA_OUTPUT, PAGING_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotListEmails')
export const hubspotListEmailsTool: ToolConfig<HubSpotListEmailsParams, HubSpotListEmailsResponse> =
{
id: 'hubspot_list_emails',
name: 'List Emails from HubSpot',
description: 'Retrieve all email engagements from HubSpot account with pagination support',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
limit: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results per page (max 100, default 10)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page of results (from previous response)',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot property names to return (e.g., "hs_email_subject,hs_email_text,hs_timestamp")',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of object types to retrieve associated IDs for (e.g., "contacts,companies,deals")',
},
},
request: {
url: (params) => {
const baseUrl = 'https://api.hubapi.com/crm/v3/objects/emails'
const queryParams = new URLSearchParams()
if (params.limit) {
queryParams.append('limit', params.limit)
}
if (params.after) {
queryParams.append('after', params.after)
}
if (params.properties) {
queryParams.append('properties', params.properties)
}
if (params.associations) {
queryParams.append('associations', params.associations)
}
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to list emails from HubSpot')
}
return {
success: true,
output: {
emails: data.results || [],
paging: data.paging ?? null,
metadata: {
totalReturned: data.results?.length || 0,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
emails: EMAILS_ARRAY_OUTPUT,
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
+109
View File
@@ -0,0 +1,109 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotListLineItemsParams,
HubSpotListLineItemsResponse,
} from '@/tools/hubspot/types'
import { LINE_ITEMS_ARRAY_OUTPUT, METADATA_OUTPUT, PAGING_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotListLineItems')
export const hubspotListLineItemsTool: ToolConfig<
HubSpotListLineItemsParams,
HubSpotListLineItemsResponse
> = {
id: 'hubspot_list_line_items',
name: 'List Line Items from HubSpot',
description: 'Retrieve all line items from HubSpot account with pagination support',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
limit: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results per page (max 100, default 10)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page of results (from previous response)',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot property names to return (e.g., "name,quantity,price,amount")',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of object types to retrieve associated IDs for (e.g., "deals,quotes")',
},
},
request: {
url: (params) => {
const baseUrl = 'https://api.hubapi.com/crm/v3/objects/line_items'
const queryParams = new URLSearchParams()
if (params.limit) queryParams.append('limit', params.limit)
if (params.after) queryParams.append('after', params.after)
if (params.properties) queryParams.append('properties', params.properties)
if (params.associations) queryParams.append('associations', params.associations)
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to list line items from HubSpot')
}
return {
success: true,
output: {
lineItems: data.results || [],
paging: data.paging ?? null,
metadata: {
totalReturned: data.results?.length || 0,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
lineItems: LINE_ITEMS_ARRAY_OUTPUT,
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
+115
View File
@@ -0,0 +1,115 @@
import { createLogger } from '@sim/logger'
import type { HubSpotListListsParams, HubSpotListListsResponse } from '@/tools/hubspot/types'
import {
LISTS_ARRAY_OUTPUT,
METADATA_OUTPUT_PROPERTIES,
PAGING_OUTPUT,
} from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotListLists')
export const hubspotListListsTool: ToolConfig<HubSpotListListsParams, HubSpotListListsResponse> = {
id: 'hubspot_list_lists',
name: 'List Lists from HubSpot',
description: 'Search and retrieve lists from HubSpot account',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
query: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search query to filter lists by name. Leave empty to return all lists.',
},
count: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return (default 20, max 500)',
},
offset: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination offset for next page of results (use the offset value from previous response)',
},
},
request: {
url: () => 'https://api.hubapi.com/crm/v3/lists/search',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
const body: Record<string, unknown> = {
offset: params.offset ? Number(params.offset) : 0,
}
if (params.query) body.query = params.query
if (params.count) body.count = Number(params.count)
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to list lists from HubSpot')
}
const lists = data.lists ?? []
return {
success: true,
output: {
lists,
paging:
data.hasMore === true && data.offset != null
? { next: { after: String(data.offset) } }
: undefined,
metadata: {
totalReturned: lists.length,
total: data.total ?? null,
hasMore: data.hasMore === true,
},
success: true,
},
}
},
outputs: {
lists: LISTS_ARRAY_OUTPUT,
paging: PAGING_OUTPUT,
metadata: {
type: 'object',
description: 'Response metadata',
properties: {
...METADATA_OUTPUT_PROPERTIES,
total: {
type: 'number',
description: 'Total number of lists matching the query',
optional: true,
},
},
},
success: { type: 'boolean', description: 'Operation success status' },
},
}
@@ -0,0 +1,98 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotListMarketingEventsParams,
HubSpotListMarketingEventsResponse,
} from '@/tools/hubspot/types'
import {
MARKETING_EVENTS_ARRAY_OUTPUT,
METADATA_OUTPUT,
PAGING_OUTPUT,
} from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotListMarketingEvents')
export const hubspotListMarketingEventsTool: ToolConfig<
HubSpotListMarketingEventsParams,
HubSpotListMarketingEventsResponse
> = {
id: 'hubspot_list_marketing_events',
name: 'List Marketing Events from HubSpot',
description: 'Retrieve all marketing events from HubSpot account with pagination support',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
limit: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results per page (max 100, default 10)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page of results (from previous response)',
},
},
request: {
url: (params) => {
const baseUrl = 'https://api.hubapi.com/marketing/marketing-events/v3'
const queryParams = new URLSearchParams()
if (params.limit) queryParams.append('limit', params.limit)
if (params.after) queryParams.append('after', params.after)
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to list marketing events from HubSpot')
}
const results = data.results || []
return {
success: true,
output: {
events: results,
paging: data.paging ?? null,
metadata: {
totalReturned: results.length,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
events: MARKETING_EVENTS_ARRAY_OUTPUT,
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
+116
View File
@@ -0,0 +1,116 @@
import { createLogger } from '@sim/logger'
import type { HubSpotListNotesParams, HubSpotListNotesResponse } from '@/tools/hubspot/types'
import { METADATA_OUTPUT, NOTES_ARRAY_OUTPUT, PAGING_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotListNotes')
export const hubspotListNotesTool: ToolConfig<HubSpotListNotesParams, HubSpotListNotesResponse> = {
id: 'hubspot_list_notes',
name: 'List Notes from HubSpot',
description: 'Retrieve all notes from HubSpot account with pagination support',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
limit: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results per page (max 100, default 10)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page of results (from previous response)',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot property names to return (e.g., "hs_note_body,hs_timestamp,hubspot_owner_id")',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of object types to retrieve associated IDs for (e.g., "contacts,companies,deals")',
},
},
request: {
url: (params) => {
const baseUrl = 'https://api.hubapi.com/crm/v3/objects/notes'
const queryParams = new URLSearchParams()
if (params.limit) {
queryParams.append('limit', params.limit)
}
if (params.after) {
queryParams.append('after', params.after)
}
if (params.properties) {
queryParams.append('properties', params.properties)
}
if (params.associations) {
queryParams.append('associations', params.associations)
}
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to list notes from HubSpot')
}
return {
success: true,
output: {
notes: data.results || [],
paging: data.paging ?? null,
metadata: {
totalReturned: data.results?.length || 0,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
notes: NOTES_ARRAY_OUTPUT,
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
+95
View File
@@ -0,0 +1,95 @@
import { createLogger } from '@sim/logger'
import type { HubSpotListOwnersParams, HubSpotListOwnersResponse } from '@/tools/hubspot/types'
import { METADATA_OUTPUT, OWNERS_ARRAY_OUTPUT, PAGING_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotListOwners')
export const hubspotListOwnersTool: ToolConfig<HubSpotListOwnersParams, HubSpotListOwnersResponse> =
{
id: 'hubspot_list_owners',
name: 'List Owners from HubSpot',
description: 'Retrieve all owners from HubSpot account with pagination support',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
limit: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results per page (max 100, default 100)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page of results (from previous response)',
},
email: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter owners by email address',
},
},
request: {
url: (params) => {
const baseUrl = 'https://api.hubapi.com/crm/v3/owners'
const queryParams = new URLSearchParams()
if (params.limit) queryParams.append('limit', params.limit)
if (params.after) queryParams.append('after', params.after)
if (params.email) queryParams.append('email', params.email)
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to list owners from HubSpot')
}
return {
success: true,
output: {
owners: data.results || [],
paging: data.paging ?? null,
metadata: {
totalReturned: data.results?.length || 0,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
owners: OWNERS_ARRAY_OUTPUT,
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
+104
View File
@@ -0,0 +1,104 @@
import { createLogger } from '@sim/logger'
import type { HubSpotListQuotesParams, HubSpotListQuotesResponse } from '@/tools/hubspot/types'
import { METADATA_OUTPUT, PAGING_OUTPUT, QUOTES_ARRAY_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotListQuotes')
export const hubspotListQuotesTool: ToolConfig<HubSpotListQuotesParams, HubSpotListQuotesResponse> =
{
id: 'hubspot_list_quotes',
name: 'List Quotes from HubSpot',
description: 'Retrieve all quotes from HubSpot account with pagination support',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
limit: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results per page (max 100, default 10)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page of results (from previous response)',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot property names to return (e.g., "hs_title,hs_expiration_date,hs_status")',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of object types to retrieve associated IDs for (e.g., "deals,line_items")',
},
},
request: {
url: (params) => {
const baseUrl = 'https://api.hubapi.com/crm/v3/objects/quotes'
const queryParams = new URLSearchParams()
if (params.limit) queryParams.append('limit', params.limit)
if (params.after) queryParams.append('after', params.after)
if (params.properties) queryParams.append('properties', params.properties)
if (params.associations) queryParams.append('associations', params.associations)
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to list quotes from HubSpot')
}
return {
success: true,
output: {
quotes: data.results || [],
paging: data.paging ?? null,
metadata: {
totalReturned: data.results?.length || 0,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
quotes: QUOTES_ARRAY_OUTPUT,
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
+106
View File
@@ -0,0 +1,106 @@
import { createLogger } from '@sim/logger'
import type { HubSpotListTicketsParams, HubSpotListTicketsResponse } from '@/tools/hubspot/types'
import { METADATA_OUTPUT, PAGING_OUTPUT, TICKETS_ARRAY_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotListTickets')
export const hubspotListTicketsTool: ToolConfig<
HubSpotListTicketsParams,
HubSpotListTicketsResponse
> = {
id: 'hubspot_list_tickets',
name: 'List Tickets from HubSpot',
description: 'Retrieve all tickets from HubSpot account with pagination support',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
limit: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results per page (max 100, default 10)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page of results (from previous response)',
},
properties: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of HubSpot property names to return (e.g., "subject,content,hs_ticket_priority")',
},
associations: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Comma-separated list of object types to retrieve associated IDs for (e.g., "contacts,companies")',
},
},
request: {
url: (params) => {
const baseUrl = 'https://api.hubapi.com/crm/v3/objects/tickets'
const queryParams = new URLSearchParams()
if (params.limit) queryParams.append('limit', params.limit)
if (params.after) queryParams.append('after', params.after)
if (params.properties) queryParams.append('properties', params.properties)
if (params.associations) queryParams.append('associations', params.associations)
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'GET',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to list tickets from HubSpot')
}
return {
success: true,
output: {
tickets: data.results || [],
paging: data.paging ?? null,
metadata: {
totalReturned: data.results?.length || 0,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
tickets: TICKETS_ARRAY_OUTPUT,
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
+173
View File
@@ -0,0 +1,173 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotSearchCompaniesParams,
HubSpotSearchCompaniesResponse,
} from '@/tools/hubspot/types'
import { COMPANIES_ARRAY_OUTPUT, METADATA_OUTPUT, PAGING_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotSearchCompanies')
export const hubspotSearchCompaniesTool: ToolConfig<
HubSpotSearchCompaniesParams,
HubSpotSearchCompaniesResponse
> = {
id: 'hubspot_search_companies',
name: 'Search Companies in HubSpot',
description: 'Search for companies in HubSpot using filters, sorting, and queries',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
filterGroups: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of filter groups as JSON. Each group contains "filters" array with objects having "propertyName", "operator" (e.g., "EQ", "CONTAINS_TOKEN", "GT"), and "value"',
},
sorts: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of sort objects as JSON with "propertyName" and "direction" ("ASCENDING" or "DESCENDING")',
},
query: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Search query string to match against company name, domain, and other text fields',
},
properties: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of HubSpot property names to return (e.g., ["name", "domain", "industry"])',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return (max 100)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page (from previous response)',
},
},
request: {
url: () => 'https://api.hubapi.com/crm/v3/objects/companies/search',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
const body: any = {}
if (params.filterGroups) {
let parsedFilterGroups = params.filterGroups
if (typeof params.filterGroups === 'string') {
try {
parsedFilterGroups = JSON.parse(params.filterGroups)
} catch (e) {
throw new Error(`Invalid JSON for filterGroups: ${(e as Error).message}`)
}
}
if (Array.isArray(parsedFilterGroups) && parsedFilterGroups.length > 0) {
body.filterGroups = parsedFilterGroups
}
}
if (params.sorts) {
let parsedSorts = params.sorts
if (typeof params.sorts === 'string') {
try {
parsedSorts = JSON.parse(params.sorts)
} catch (e) {
throw new Error(`Invalid JSON for sorts: ${(e as Error).message}`)
}
}
if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {
body.sorts = parsedSorts
}
}
if (params.query) {
body.query = params.query
}
if (params.properties) {
let parsedProperties = params.properties
if (typeof params.properties === 'string') {
try {
parsedProperties = JSON.parse(params.properties)
} catch (e) {
throw new Error(`Invalid JSON for properties: ${(e as Error).message}`)
}
}
if (Array.isArray(parsedProperties) && parsedProperties.length > 0) {
body.properties = parsedProperties
}
}
if (params.limit) {
body.limit = params.limit
}
if (params.after) {
body.after = params.after
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to search companies in HubSpot')
}
return {
success: true,
output: {
companies: data.results || [],
total: data.total ?? 0,
paging: data.paging ?? null,
metadata: {
totalReturned: data.results?.length || 0,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
companies: COMPANIES_ARRAY_OUTPUT,
total: { type: 'number', description: 'Total number of matching companies', optional: true },
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
+173
View File
@@ -0,0 +1,173 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotSearchContactsParams,
HubSpotSearchContactsResponse,
} from '@/tools/hubspot/types'
import { CONTACTS_ARRAY_OUTPUT, METADATA_OUTPUT, PAGING_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotSearchContacts')
export const hubspotSearchContactsTool: ToolConfig<
HubSpotSearchContactsParams,
HubSpotSearchContactsResponse
> = {
id: 'hubspot_search_contacts',
name: 'Search Contacts in HubSpot',
description: 'Search for contacts in HubSpot using filters, sorting, and queries',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
filterGroups: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of filter groups as JSON. Each group contains "filters" array with objects having "propertyName", "operator" (e.g., "EQ", "CONTAINS_TOKEN", "GT"), and "value"',
},
sorts: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of sort objects as JSON with "propertyName" and "direction" ("ASCENDING" or "DESCENDING")',
},
query: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Search query string to match against contact name, email, and other text fields',
},
properties: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of HubSpot property names to return (e.g., ["email", "firstname", "lastname", "phone"])',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return (max 100)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page (from previous response)',
},
},
request: {
url: () => 'https://api.hubapi.com/crm/v3/objects/contacts/search',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
const body: any = {}
if (params.filterGroups) {
let parsedFilterGroups = params.filterGroups
if (typeof params.filterGroups === 'string') {
try {
parsedFilterGroups = JSON.parse(params.filterGroups)
} catch (e) {
throw new Error(`Invalid JSON for filterGroups: ${(e as Error).message}`)
}
}
if (Array.isArray(parsedFilterGroups) && parsedFilterGroups.length > 0) {
body.filterGroups = parsedFilterGroups
}
}
if (params.sorts) {
let parsedSorts = params.sorts
if (typeof params.sorts === 'string') {
try {
parsedSorts = JSON.parse(params.sorts)
} catch (e) {
throw new Error(`Invalid JSON for sorts: ${(e as Error).message}`)
}
}
if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {
body.sorts = parsedSorts
}
}
if (params.query) {
body.query = params.query
}
if (params.properties) {
let parsedProperties = params.properties
if (typeof params.properties === 'string') {
try {
parsedProperties = JSON.parse(params.properties)
} catch (e) {
throw new Error(`Invalid JSON for properties: ${(e as Error).message}`)
}
}
if (Array.isArray(parsedProperties) && parsedProperties.length > 0) {
body.properties = parsedProperties
}
}
if (params.limit) {
body.limit = params.limit
}
if (params.after) {
body.after = params.after
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to search contacts in HubSpot')
}
return {
success: true,
output: {
contacts: data.results || [],
total: data.total ?? 0,
paging: data.paging ?? null,
metadata: {
totalReturned: data.results?.length || 0,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
contacts: CONTACTS_ARRAY_OUTPUT,
total: { type: 'number', description: 'Total number of matching contacts', optional: true },
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
+152
View File
@@ -0,0 +1,152 @@
import { createLogger } from '@sim/logger'
import type { HubSpotSearchDealsParams, HubSpotSearchDealsResponse } from '@/tools/hubspot/types'
import { DEALS_ARRAY_OUTPUT, METADATA_OUTPUT, PAGING_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotSearchDeals')
export const hubspotSearchDealsTool: ToolConfig<
HubSpotSearchDealsParams,
HubSpotSearchDealsResponse
> = {
id: 'hubspot_search_deals',
name: 'Search Deals in HubSpot',
description: 'Search for deals in HubSpot using filters, sorting, and queries',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
filterGroups: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of filter groups as JSON. Each group contains "filters" array with objects having "propertyName", "operator" (e.g., "EQ", "NEQ", "CONTAINS_TOKEN", "NOT_CONTAINS_TOKEN"), and "value"',
},
sorts: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of sort objects as JSON with "propertyName" and "direction" ("ASCENDING" or "DESCENDING")',
},
query: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search query string to match against deal name and other text fields',
},
properties: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of HubSpot property names to return (e.g., ["dealname", "amount", "dealstage"])',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return (max 200)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page (from previous response)',
},
},
request: {
url: () => 'https://api.hubapi.com/crm/v3/objects/deals/search',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
const body: Record<string, unknown> = {}
if (params.filterGroups) {
let parsed = params.filterGroups
if (typeof parsed === 'string') {
try {
parsed = JSON.parse(parsed)
} catch (e) {
throw new Error(`Invalid JSON for filterGroups: ${(e as Error).message}`)
}
}
if (Array.isArray(parsed) && parsed.length > 0) body.filterGroups = parsed
}
if (params.sorts) {
let parsed = params.sorts
if (typeof parsed === 'string') {
try {
parsed = JSON.parse(parsed)
} catch (e) {
throw new Error(`Invalid JSON for sorts: ${(e as Error).message}`)
}
}
if (Array.isArray(parsed) && parsed.length > 0) body.sorts = parsed
}
if (params.query) body.query = params.query
if (params.properties) {
let parsed = params.properties
if (typeof parsed === 'string') {
try {
parsed = JSON.parse(parsed)
} catch (e) {
throw new Error(`Invalid JSON for properties: ${(e as Error).message}`)
}
}
if (Array.isArray(parsed) && parsed.length > 0) body.properties = parsed
}
if (params.limit) body.limit = params.limit
if (params.after) body.after = params.after
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to search deals in HubSpot')
}
return {
success: true,
output: {
deals: data.results || [],
total: data.total ?? 0,
paging: data.paging ?? null,
metadata: {
totalReturned: data.results?.length || 0,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
deals: DEALS_ARRAY_OUTPUT,
total: { type: 'number', description: 'Total number of matching deals', optional: true },
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
+169
View File
@@ -0,0 +1,169 @@
import { createLogger } from '@sim/logger'
import type { HubSpotSearchEmailsParams, HubSpotSearchEmailsResponse } from '@/tools/hubspot/types'
import { EMAILS_ARRAY_OUTPUT, METADATA_OUTPUT, PAGING_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotSearchEmails')
export const hubspotSearchEmailsTool: ToolConfig<
HubSpotSearchEmailsParams,
HubSpotSearchEmailsResponse
> = {
id: 'hubspot_search_emails',
name: 'Search Emails in HubSpot',
description: 'Search for email engagements in HubSpot using filters, sorting, and queries',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
filterGroups: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of filter groups as JSON. Each group contains "filters" array with objects having "propertyName", "operator" (e.g., "EQ", "CONTAINS_TOKEN", "GT"), and "value"',
},
sorts: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of sort objects as JSON with "propertyName" and "direction" ("ASCENDING" or "DESCENDING")',
},
query: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search query string to match against email text fields',
},
properties: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of HubSpot property names to return (e.g., ["hs_email_subject", "hs_email_text", "hs_timestamp"])',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return (max 100)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page (from previous response)',
},
},
request: {
url: () => 'https://api.hubapi.com/crm/v3/objects/emails/search',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
const body: any = {}
if (params.filterGroups) {
let parsedFilterGroups = params.filterGroups
if (typeof params.filterGroups === 'string') {
try {
parsedFilterGroups = JSON.parse(params.filterGroups)
} catch (e) {
throw new Error(`Invalid JSON for filterGroups: ${(e as Error).message}`)
}
}
if (Array.isArray(parsedFilterGroups) && parsedFilterGroups.length > 0) {
body.filterGroups = parsedFilterGroups
}
}
if (params.sorts) {
let parsedSorts = params.sorts
if (typeof params.sorts === 'string') {
try {
parsedSorts = JSON.parse(params.sorts)
} catch (e) {
throw new Error(`Invalid JSON for sorts: ${(e as Error).message}`)
}
}
if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {
body.sorts = parsedSorts
}
}
if (params.query) {
body.query = params.query
}
if (params.properties) {
let parsedProperties = params.properties
if (typeof params.properties === 'string') {
try {
parsedProperties = JSON.parse(params.properties)
} catch (e) {
throw new Error(`Invalid JSON for properties: ${(e as Error).message}`)
}
}
if (Array.isArray(parsedProperties) && parsedProperties.length > 0) {
body.properties = parsedProperties
}
}
if (params.limit) {
body.limit = params.limit
}
if (params.after) {
body.after = params.after
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to search emails in HubSpot')
}
return {
success: true,
output: {
emails: data.results || [],
total: data.total ?? 0,
paging: data.paging ?? null,
metadata: {
totalReturned: data.results?.length || 0,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
emails: EMAILS_ARRAY_OUTPUT,
total: { type: 'number', description: 'Total number of matching emails', optional: true },
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
+169
View File
@@ -0,0 +1,169 @@
import { createLogger } from '@sim/logger'
import type { HubSpotSearchNotesParams, HubSpotSearchNotesResponse } from '@/tools/hubspot/types'
import { METADATA_OUTPUT, NOTES_ARRAY_OUTPUT, PAGING_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotSearchNotes')
export const hubspotSearchNotesTool: ToolConfig<
HubSpotSearchNotesParams,
HubSpotSearchNotesResponse
> = {
id: 'hubspot_search_notes',
name: 'Search Notes in HubSpot',
description: 'Search for notes in HubSpot using filters, sorting, and queries',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
filterGroups: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of filter groups as JSON. Each group contains "filters" array with objects having "propertyName", "operator" (e.g., "EQ", "CONTAINS_TOKEN", "GT"), and "value"',
},
sorts: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of sort objects as JSON with "propertyName" and "direction" ("ASCENDING" or "DESCENDING")',
},
query: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search query string to match against note text fields',
},
properties: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of HubSpot property names to return (e.g., ["hs_note_body", "hs_timestamp", "hubspot_owner_id"])',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return (max 100)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page (from previous response)',
},
},
request: {
url: () => 'https://api.hubapi.com/crm/v3/objects/notes/search',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
const body: any = {}
if (params.filterGroups) {
let parsedFilterGroups = params.filterGroups
if (typeof params.filterGroups === 'string') {
try {
parsedFilterGroups = JSON.parse(params.filterGroups)
} catch (e) {
throw new Error(`Invalid JSON for filterGroups: ${(e as Error).message}`)
}
}
if (Array.isArray(parsedFilterGroups) && parsedFilterGroups.length > 0) {
body.filterGroups = parsedFilterGroups
}
}
if (params.sorts) {
let parsedSorts = params.sorts
if (typeof params.sorts === 'string') {
try {
parsedSorts = JSON.parse(params.sorts)
} catch (e) {
throw new Error(`Invalid JSON for sorts: ${(e as Error).message}`)
}
}
if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {
body.sorts = parsedSorts
}
}
if (params.query) {
body.query = params.query
}
if (params.properties) {
let parsedProperties = params.properties
if (typeof params.properties === 'string') {
try {
parsedProperties = JSON.parse(params.properties)
} catch (e) {
throw new Error(`Invalid JSON for properties: ${(e as Error).message}`)
}
}
if (Array.isArray(parsedProperties) && parsedProperties.length > 0) {
body.properties = parsedProperties
}
}
if (params.limit) {
body.limit = params.limit
}
if (params.after) {
body.after = params.after
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to search notes in HubSpot')
}
return {
success: true,
output: {
notes: data.results || [],
total: data.total ?? 0,
paging: data.paging ?? null,
metadata: {
totalReturned: data.results?.length || 0,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
notes: NOTES_ARRAY_OUTPUT,
total: { type: 'number', description: 'Total number of matching notes', optional: true },
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
+155
View File
@@ -0,0 +1,155 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotSearchTicketsParams,
HubSpotSearchTicketsResponse,
} from '@/tools/hubspot/types'
import { METADATA_OUTPUT, PAGING_OUTPUT, TICKETS_ARRAY_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotSearchTickets')
export const hubspotSearchTicketsTool: ToolConfig<
HubSpotSearchTicketsParams,
HubSpotSearchTicketsResponse
> = {
id: 'hubspot_search_tickets',
name: 'Search Tickets in HubSpot',
description: 'Search for tickets in HubSpot using filters, sorting, and queries',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
filterGroups: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of filter groups as JSON. Each group contains "filters" array with objects having "propertyName", "operator" (e.g., "EQ", "NEQ", "CONTAINS_TOKEN", "NOT_CONTAINS_TOKEN"), and "value"',
},
sorts: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of sort objects as JSON with "propertyName" and "direction" ("ASCENDING" or "DESCENDING")',
},
query: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search query string to match against ticket subject and other text fields',
},
properties: {
type: 'array',
required: false,
visibility: 'user-or-llm',
description:
'Array of HubSpot property names to return (e.g., ["subject", "content", "hs_ticket_priority"])',
},
limit: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Maximum number of results to return (max 200)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Pagination cursor for next page (from previous response)',
},
},
request: {
url: () => 'https://api.hubapi.com/crm/v3/objects/tickets/search',
method: 'POST',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
const body: Record<string, unknown> = {}
if (params.filterGroups) {
let parsed = params.filterGroups
if (typeof parsed === 'string') {
try {
parsed = JSON.parse(parsed)
} catch (e) {
throw new Error(`Invalid JSON for filterGroups: ${(e as Error).message}`)
}
}
if (Array.isArray(parsed) && parsed.length > 0) body.filterGroups = parsed
}
if (params.sorts) {
let parsed = params.sorts
if (typeof parsed === 'string') {
try {
parsed = JSON.parse(parsed)
} catch (e) {
throw new Error(`Invalid JSON for sorts: ${(e as Error).message}`)
}
}
if (Array.isArray(parsed) && parsed.length > 0) body.sorts = parsed
}
if (params.query) body.query = params.query
if (params.properties) {
let parsed = params.properties
if (typeof parsed === 'string') {
try {
parsed = JSON.parse(parsed)
} catch (e) {
throw new Error(`Invalid JSON for properties: ${(e as Error).message}`)
}
}
if (Array.isArray(parsed) && parsed.length > 0) body.properties = parsed
}
if (params.limit) body.limit = params.limit
if (params.after) body.after = params.after
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to search tickets in HubSpot')
}
return {
success: true,
output: {
tickets: data.results || [],
total: data.total ?? 0,
paging: data.paging ?? null,
metadata: {
totalReturned: data.results?.length || 0,
hasMore: !!data.paging?.next,
},
success: true,
},
}
},
outputs: {
tickets: TICKETS_ARRAY_OUTPUT,
total: { type: 'number', description: 'Total number of matching tickets', optional: true },
paging: PAGING_OUTPUT,
metadata: METADATA_OUTPUT,
success: { type: 'boolean', description: 'Operation success status' },
},
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,101 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotUpdateAppointmentParams,
HubSpotUpdateAppointmentResponse,
} from '@/tools/hubspot/types'
import { APPOINTMENT_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotUpdateAppointment')
export const hubspotUpdateAppointmentTool: ToolConfig<
HubSpotUpdateAppointmentParams,
HubSpotUpdateAppointmentResponse
> = {
id: 'hubspot_update_appointment',
name: 'Update Appointment in HubSpot',
description: 'Update an existing appointment in HubSpot by ID',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
appointmentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The HubSpot appointment ID to update',
},
idProperty: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Property to use as unique identifier. If not specified, uses record ID',
},
properties: {
type: 'object',
required: true,
visibility: 'user-or-llm',
description:
'Appointment properties to update as JSON object (e.g., {"hs_appointment_name": "Updated Call", "hs_appointment_start": "2024-01-15T10:00:00Z"})',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.hubapi.com/crm/v3/objects/appointments/${params.appointmentId.trim()}`
const queryParams = new URLSearchParams()
if (params.idProperty) queryParams.append('idProperty', params.idProperty)
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'PATCH',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
let properties = params.properties
if (typeof properties === 'string') {
try {
properties = JSON.parse(properties)
} catch (e) {
throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.')
}
}
return { properties }
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to update appointment in HubSpot')
}
return {
success: true,
output: { appointment: data, appointmentId: data.id, success: true },
}
},
outputs: {
appointment: APPOINTMENT_OBJECT_OUTPUT,
appointmentId: { type: 'string', description: 'The updated appointment ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+112
View File
@@ -0,0 +1,112 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotUpdateCompanyParams,
HubSpotUpdateCompanyResponse,
} from '@/tools/hubspot/types'
import { COMPANY_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotUpdateCompany')
export const hubspotUpdateCompanyTool: ToolConfig<
HubSpotUpdateCompanyParams,
HubSpotUpdateCompanyResponse
> = {
id: 'hubspot_update_company',
name: 'Update Company in HubSpot',
description: 'Update an existing company in HubSpot by ID or domain',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
companyId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The HubSpot company ID (numeric string) or domain of the company to update',
},
idProperty: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Property to use as unique identifier (e.g., "domain"). If not specified, uses record ID',
},
properties: {
type: 'object',
required: true,
visibility: 'user-or-llm',
description:
'Company properties to update as JSON object (e.g., {"name": "New Name", "industry": "Finance"})',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.hubapi.com/crm/v3/objects/companies/${params.companyId.trim()}`
if (params.idProperty) {
return `${baseUrl}?idProperty=${params.idProperty}`
}
return baseUrl
},
method: 'PATCH',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
let properties = params.properties
if (typeof properties === 'string') {
try {
properties = JSON.parse(properties)
} catch (e) {
throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.')
}
}
return {
properties,
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to update company in HubSpot')
}
return {
success: true,
output: {
company: data,
companyId: data.id,
success: true,
},
}
},
outputs: {
company: COMPANY_OBJECT_OUTPUT,
companyId: { type: 'string', description: 'The updated company ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+112
View File
@@ -0,0 +1,112 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotUpdateContactParams,
HubSpotUpdateContactResponse,
} from '@/tools/hubspot/types'
import { CONTACT_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotUpdateContact')
export const hubspotUpdateContactTool: ToolConfig<
HubSpotUpdateContactParams,
HubSpotUpdateContactResponse
> = {
id: 'hubspot_update_contact',
name: 'Update Contact in HubSpot',
description: 'Update an existing contact in HubSpot by ID or email',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
contactId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The HubSpot contact ID (numeric string) or email of the contact to update',
},
idProperty: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Property to use as unique identifier (e.g., "email"). If not specified, uses record ID',
},
properties: {
type: 'object',
required: true,
visibility: 'user-or-llm',
description:
'Contact properties to update as JSON object (e.g., {"firstname": "John", "phone": "+1234567890"})',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.hubapi.com/crm/v3/objects/contacts/${params.contactId.trim()}`
if (params.idProperty) {
return `${baseUrl}?idProperty=${params.idProperty}`
}
return baseUrl
},
method: 'PATCH',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
let properties = params.properties
if (typeof properties === 'string') {
try {
properties = JSON.parse(properties)
} catch (e) {
throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.')
}
}
return {
properties,
}
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to update contact in HubSpot')
}
return {
success: true,
output: {
contact: data,
contactId: data.id,
success: true,
},
}
},
outputs: {
contact: CONTACT_OBJECT_OUTPUT,
contactId: { type: 'string', description: 'The updated contact ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+98
View File
@@ -0,0 +1,98 @@
import { createLogger } from '@sim/logger'
import type { HubSpotUpdateDealParams, HubSpotUpdateDealResponse } from '@/tools/hubspot/types'
import { DEAL_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotUpdateDeal')
export const hubspotUpdateDealTool: ToolConfig<HubSpotUpdateDealParams, HubSpotUpdateDealResponse> =
{
id: 'hubspot_update_deal',
name: 'Update Deal in HubSpot',
description: 'Update an existing deal in HubSpot by ID',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
dealId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The HubSpot deal ID to update',
},
idProperty: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Property to use as unique identifier. If not specified, uses record ID',
},
properties: {
type: 'object',
required: true,
visibility: 'user-or-llm',
description:
'Deal properties to update as JSON object (e.g., {"amount": "10000", "dealstage": "closedwon"})',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.hubapi.com/crm/v3/objects/deals/${params.dealId.trim()}`
const queryParams = new URLSearchParams()
if (params.idProperty) queryParams.append('idProperty', params.idProperty)
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'PATCH',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
let properties = params.properties
if (typeof properties === 'string') {
try {
properties = JSON.parse(properties)
} catch (e) {
throw new Error(
'Invalid JSON format for properties. Please provide a valid JSON object.'
)
}
}
return { properties }
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to update deal in HubSpot')
}
return {
success: true,
output: { deal: data, dealId: data.id, success: true },
}
},
outputs: {
deal: DEAL_OBJECT_OUTPUT,
dealId: { type: 'string', description: 'The updated deal ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+101
View File
@@ -0,0 +1,101 @@
import { createLogger } from '@sim/logger'
import type {
HubSpotUpdateLineItemParams,
HubSpotUpdateLineItemResponse,
} from '@/tools/hubspot/types'
import { LINE_ITEM_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotUpdateLineItem')
export const hubspotUpdateLineItemTool: ToolConfig<
HubSpotUpdateLineItemParams,
HubSpotUpdateLineItemResponse
> = {
id: 'hubspot_update_line_item',
name: 'Update Line Item in HubSpot',
description: 'Update an existing line item in HubSpot by ID',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
lineItemId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The HubSpot line item ID to update',
},
idProperty: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Property to use as unique identifier. If not specified, uses record ID',
},
properties: {
type: 'object',
required: true,
visibility: 'user-or-llm',
description:
'Line item properties to update as JSON object (e.g., {"quantity": "5", "price": "25.00"})',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.hubapi.com/crm/v3/objects/line_items/${params.lineItemId.trim()}`
const queryParams = new URLSearchParams()
if (params.idProperty) queryParams.append('idProperty', params.idProperty)
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'PATCH',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
let properties = params.properties
if (typeof properties === 'string') {
try {
properties = JSON.parse(properties)
} catch (e) {
throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.')
}
}
return { properties }
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to update line item in HubSpot')
}
return {
success: true,
output: { lineItem: data, lineItemId: data.id, success: true },
}
},
outputs: {
lineItem: LINE_ITEM_OBJECT_OUTPUT,
lineItemId: { type: 'string', description: 'The updated line item ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}
+98
View File
@@ -0,0 +1,98 @@
import { createLogger } from '@sim/logger'
import type { HubSpotUpdateTicketParams, HubSpotUpdateTicketResponse } from '@/tools/hubspot/types'
import { TICKET_OBJECT_OUTPUT } from '@/tools/hubspot/types'
import type { ToolConfig } from '@/tools/types'
const logger = createLogger('HubSpotUpdateTicket')
export const hubspotUpdateTicketTool: ToolConfig<
HubSpotUpdateTicketParams,
HubSpotUpdateTicketResponse
> = {
id: 'hubspot_update_ticket',
name: 'Update Ticket in HubSpot',
description: 'Update an existing ticket in HubSpot by ID',
version: '1.0.0',
oauth: {
required: true,
provider: 'hubspot',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'The access token for the HubSpot API',
},
ticketId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The HubSpot ticket ID to update',
},
idProperty: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Property to use as unique identifier. If not specified, uses record ID',
},
properties: {
type: 'object',
required: true,
visibility: 'user-or-llm',
description:
'Ticket properties to update as JSON object (e.g., {"subject": "Updated subject", "hs_ticket_priority": "HIGH"})',
},
},
request: {
url: (params) => {
const baseUrl = `https://api.hubapi.com/crm/v3/objects/tickets/${params.ticketId.trim()}`
const queryParams = new URLSearchParams()
if (params.idProperty) queryParams.append('idProperty', params.idProperty)
const queryString = queryParams.toString()
return queryString ? `${baseUrl}?${queryString}` : baseUrl
},
method: 'PATCH',
headers: (params) => {
if (!params.accessToken) {
throw new Error('Access token is required')
}
return {
Authorization: `Bearer ${params.accessToken}`,
'Content-Type': 'application/json',
}
},
body: (params) => {
let properties = params.properties
if (typeof properties === 'string') {
try {
properties = JSON.parse(properties)
} catch (e) {
throw new Error('Invalid JSON format for properties. Please provide a valid JSON object.')
}
}
return { properties }
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
if (!response.ok) {
logger.error('HubSpot API request failed', { data, status: response.status })
throw new Error(data.message || 'Failed to update ticket in HubSpot')
}
return {
success: true,
output: { ticket: data, ticketId: data.id, success: true },
}
},
outputs: {
ticket: TICKET_OBJECT_OUTPUT,
ticketId: { type: 'string', description: 'The updated ticket ID' },
success: { type: 'boolean', description: 'Operation success status' },
},
}