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
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:
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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'
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
@@ -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' },
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user