chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
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) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
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
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
import type {
|
||||
ApolloAccountBulkCreateParams,
|
||||
ApolloAccountBulkCreateResponse,
|
||||
} from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloAccountBulkCreateTool: ToolConfig<
|
||||
ApolloAccountBulkCreateParams,
|
||||
ApolloAccountBulkCreateResponse
|
||||
> = {
|
||||
id: 'apollo_account_bulk_create',
|
||||
name: 'Apollo Bulk Create Accounts',
|
||||
description:
|
||||
'Create up to 100 accounts at once in your Apollo database. Set run_dedupe=true to deduplicate by domain, organization_id, and name. Master key required.',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key (master key required)',
|
||||
},
|
||||
accounts: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Array of accounts to create (max 100). Each account should include a name, and may optionally include domain, phone, phone_status_cd, raw_address, owner_id, linkedin_url, facebook_url, twitter_url, salesforce_id, and hubspot_id.',
|
||||
},
|
||||
append_label_names: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Array of label names to add to ALL accounts in this request',
|
||||
},
|
||||
run_dedupe: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'When true, performs aggressive deduplication by domain, organization_id, and name (defaults to false)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.apollo.io/api/v1/accounts/bulk_create',
|
||||
method: 'POST',
|
||||
headers: (params: ApolloAccountBulkCreateParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
body: (params: ApolloAccountBulkCreateParams) => {
|
||||
const body: Record<string, unknown> = {
|
||||
accounts: params.accounts.slice(0, 100),
|
||||
}
|
||||
if (params.append_label_names?.length) {
|
||||
body.append_label_names = params.append_label_names
|
||||
}
|
||||
if (params.run_dedupe !== undefined) body.run_dedupe = params.run_dedupe
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
const createdAccounts = Array.isArray(data.created_accounts)
|
||||
? data.created_accounts
|
||||
: Array.isArray(data.accounts)
|
||||
? data.accounts
|
||||
: []
|
||||
const existingAccounts = Array.isArray(data.existing_accounts) ? data.existing_accounts : []
|
||||
const failedAccounts = Array.isArray(data.failed_accounts) ? data.failed_accounts : []
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
created_accounts: createdAccounts,
|
||||
existing_accounts: existingAccounts,
|
||||
failed_accounts: failedAccounts,
|
||||
total_submitted: createdAccounts.length + existingAccounts.length + failedAccounts.length,
|
||||
created: createdAccounts.length,
|
||||
existing: existingAccounts.length,
|
||||
failed: failedAccounts.length,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
created_accounts: {
|
||||
type: 'json',
|
||||
description: 'Array of newly created accounts',
|
||||
},
|
||||
existing_accounts: {
|
||||
type: 'json',
|
||||
description: 'Array of existing accounts returned by Apollo (when duplicates are detected)',
|
||||
},
|
||||
failed_accounts: {
|
||||
type: 'json',
|
||||
description: 'Array of accounts that failed to be created, with reasons for failure',
|
||||
},
|
||||
total_submitted: {
|
||||
type: 'number',
|
||||
description: 'Total number of accounts in the response (created + existing + failed)',
|
||||
},
|
||||
created: {
|
||||
type: 'number',
|
||||
description: 'Number of accounts successfully created',
|
||||
},
|
||||
existing: {
|
||||
type: 'number',
|
||||
description: 'Number of existing accounts found',
|
||||
},
|
||||
failed: {
|
||||
type: 'number',
|
||||
description: 'Number of accounts that failed to be created',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
import type {
|
||||
ApolloAccountBulkUpdateParams,
|
||||
ApolloAccountBulkUpdateResponse,
|
||||
} from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloAccountBulkUpdateTool: ToolConfig<
|
||||
ApolloAccountBulkUpdateParams,
|
||||
ApolloAccountBulkUpdateResponse
|
||||
> = {
|
||||
id: 'apollo_account_bulk_update',
|
||||
name: 'Apollo Bulk Update Accounts',
|
||||
description:
|
||||
'Update up to 1000 existing accounts at once in your Apollo database (higher limit than contacts!). Each account must include an id field. Master key required.',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key (master key required)',
|
||||
},
|
||||
account_ids: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Array of account IDs to update with the same values (max 1000). Use with name/owner_id for uniform updates. Use either this OR account_attributes.',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'When using account_ids, apply this name to all accounts',
|
||||
},
|
||||
owner_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'When using account_ids, apply this owner to all accounts',
|
||||
},
|
||||
account_stage_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'When using account_ids, apply this account stage to all accounts',
|
||||
},
|
||||
account_attributes: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Array of account objects with individual updates (each must include id). Example: [{"id": "acc1", "name": "Acme", "owner_id": "u1", "account_stage_id": "s1", "typed_custom_fields": {"field_id": "value"}}]',
|
||||
},
|
||||
async: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description:
|
||||
'When true, processes the update asynchronously. Only supported when using account_ids; returns 422 if used with account_attributes.',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.apollo.io/api/v1/accounts/bulk_update',
|
||||
method: 'POST',
|
||||
headers: (params: ApolloAccountBulkUpdateParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
body: (params: ApolloAccountBulkUpdateParams) => {
|
||||
const body: Record<string, unknown> = {}
|
||||
if (params.account_ids && params.account_ids.length > 0) {
|
||||
body.account_ids = params.account_ids.slice(0, 1000)
|
||||
}
|
||||
if (params.name) body.name = params.name
|
||||
if (params.owner_id) body.owner_id = params.owner_id
|
||||
if (params.account_stage_id) body.account_stage_id = params.account_stage_id
|
||||
if (params.account_attributes) {
|
||||
if (Array.isArray(params.account_attributes)) {
|
||||
if (params.account_attributes.length > 0) {
|
||||
body.account_attributes = params.account_attributes.slice(0, 1000)
|
||||
}
|
||||
} else if (
|
||||
typeof params.account_attributes === 'object' &&
|
||||
Object.keys(params.account_attributes).length > 0
|
||||
) {
|
||||
body.account_attributes = params.account_attributes
|
||||
}
|
||||
}
|
||||
const hasUpdateFields =
|
||||
body.account_attributes || body.name || body.owner_id || body.account_stage_id
|
||||
if (!hasUpdateFields) {
|
||||
throw new Error(
|
||||
'Apollo account bulk update requires update fields. Provide account_attributes (array of per-account updates with id, or single object paired with account_ids), or pair account_ids with name/owner_id to apply uniformly.'
|
||||
)
|
||||
}
|
||||
if (!body.account_ids && !body.account_attributes) {
|
||||
throw new Error(
|
||||
'Apollo account bulk update requires account_ids (with name/owner_id) or account_attributes (with embedded ids).'
|
||||
)
|
||||
}
|
||||
if (body.account_attributes && !Array.isArray(body.account_attributes) && !body.account_ids) {
|
||||
throw new Error(
|
||||
'Apollo account bulk update with object-form account_attributes requires account_ids to identify which accounts to update.'
|
||||
)
|
||||
}
|
||||
if (body.account_ids && Array.isArray(body.account_attributes)) {
|
||||
throw new Error(
|
||||
'Apollo account bulk update cannot combine account_ids with array-form account_attributes. Use account_ids with name/owner_id (or object-form account_attributes), or use array-form account_attributes alone (each entry carries its own id).'
|
||||
)
|
||||
}
|
||||
if (params.async !== undefined) body.async = params.async
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
const accounts = Array.isArray(data?.accounts) ? data.accounts : []
|
||||
const entityProgressJob = data?.entity_progress_job ?? null
|
||||
const accountIds = Array.isArray(data?.account_ids)
|
||||
? data.account_ids
|
||||
: accounts.map((a: { id?: unknown }) => a?.id).filter((id: unknown) => typeof id === 'string')
|
||||
const jobId =
|
||||
typeof data?.job_id === 'string'
|
||||
? data.job_id
|
||||
: typeof entityProgressJob?.id === 'string'
|
||||
? entityProgressJob.id
|
||||
: null
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
accounts,
|
||||
account_ids: accountIds,
|
||||
entity_progress_job: entityProgressJob,
|
||||
job_id: jobId,
|
||||
message: data?.message ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
accounts: {
|
||||
type: 'json',
|
||||
description: 'Updated accounts (synchronous response): [{id, account_stage_id, ...}]',
|
||||
},
|
||||
account_ids: {
|
||||
type: 'json',
|
||||
description: 'IDs of accounts that were updated',
|
||||
},
|
||||
entity_progress_job: {
|
||||
type: 'json',
|
||||
description: 'Async job descriptor (when async=true is passed with account_ids)',
|
||||
optional: true,
|
||||
},
|
||||
job_id: {
|
||||
type: 'string',
|
||||
description: 'Async job ID extracted from entity_progress_job',
|
||||
optional: true,
|
||||
},
|
||||
message: {
|
||||
type: 'string',
|
||||
description: 'Optional confirmation message from Apollo',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import type { ApolloAccountCreateParams, ApolloAccountCreateResponse } from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloAccountCreateTool: ToolConfig<
|
||||
ApolloAccountCreateParams,
|
||||
ApolloAccountCreateResponse
|
||||
> = {
|
||||
id: 'apollo_account_create',
|
||||
name: 'Apollo Create Account',
|
||||
description: 'Create a new account (company) in your Apollo database',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key (master key required)',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Company name (e.g., "Acme Corporation")',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Company domain without www. prefix (e.g., "acme.com")',
|
||||
},
|
||||
phone: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Primary phone number for the account',
|
||||
},
|
||||
owner_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo user ID of the account owner',
|
||||
},
|
||||
account_stage_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo ID for the account stage to assign this account to',
|
||||
},
|
||||
raw_address: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Corporate location (e.g., "San Francisco, CA, USA")',
|
||||
},
|
||||
typed_custom_fields: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Custom field values as { custom_field_id: value } map',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.apollo.io/api/v1/accounts',
|
||||
method: 'POST',
|
||||
headers: (params: ApolloAccountCreateParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
body: (params: ApolloAccountCreateParams) => {
|
||||
const body: Record<string, unknown> = { name: params.name }
|
||||
if (params.domain) body.domain = params.domain
|
||||
if (params.phone) body.phone = params.phone
|
||||
if (params.owner_id) body.owner_id = params.owner_id
|
||||
if (params.account_stage_id) body.account_stage_id = params.account_stage_id
|
||||
if (params.raw_address) body.raw_address = params.raw_address
|
||||
if (params.typed_custom_fields) body.typed_custom_fields = params.typed_custom_fields
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
const account = data.account ?? (data.id ? data : null)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
account,
|
||||
created: !!account,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
account: { type: 'json', description: 'Created account data from Apollo', optional: true },
|
||||
created: { type: 'boolean', description: 'Whether the account was successfully created' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
import type { ApolloAccountSearchParams, ApolloAccountSearchResponse } from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloAccountSearchTool: ToolConfig<
|
||||
ApolloAccountSearchParams,
|
||||
ApolloAccountSearchResponse
|
||||
> = {
|
||||
id: 'apollo_account_search',
|
||||
name: 'Apollo Search Accounts',
|
||||
description:
|
||||
"Search your team's accounts in Apollo. Display limit: 50,000 records (100 records per page, 500 pages max). Use filters to narrow results. Master key required.",
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key (master key required)',
|
||||
},
|
||||
q_organization_name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Filter accounts by organization name (partial-match search)',
|
||||
},
|
||||
account_stage_ids: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Filter by account stage IDs',
|
||||
},
|
||||
account_label_ids: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Filter by account label IDs',
|
||||
},
|
||||
sort_by_field: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Sort field: "account_last_activity_date", "account_created_at", or "account_updated_at"',
|
||||
},
|
||||
sort_ascending: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort ascending when true. Defaults to descending.',
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number for pagination (e.g., 1, 2, 3)',
|
||||
},
|
||||
per_page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page, max 100 (e.g., 25, 50, 100)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.apollo.io/api/v1/accounts/search',
|
||||
method: 'POST',
|
||||
headers: (params: ApolloAccountSearchParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
body: (params: ApolloAccountSearchParams) => {
|
||||
const body: Record<string, unknown> = {
|
||||
page: params.page || 1,
|
||||
per_page: Math.min(params.per_page || 25, 100),
|
||||
}
|
||||
if (params.q_organization_name) body.q_organization_name = params.q_organization_name
|
||||
if (params.account_stage_ids?.length) {
|
||||
body.account_stage_ids = params.account_stage_ids
|
||||
}
|
||||
if (params.account_label_ids?.length) {
|
||||
body.account_label_ids = params.account_label_ids
|
||||
}
|
||||
if (params.sort_by_field) body.sort_by_field = params.sort_by_field
|
||||
if (params.sort_ascending !== undefined) body.sort_ascending = params.sort_ascending
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
accounts: data.accounts ?? [],
|
||||
pagination: data.pagination ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
accounts: {
|
||||
type: 'json',
|
||||
description: 'Array of accounts matching the search criteria',
|
||||
},
|
||||
pagination: { type: 'json', description: 'Pagination information', optional: true },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
import type { ApolloAccountUpdateParams, ApolloAccountUpdateResponse } from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloAccountUpdateTool: ToolConfig<
|
||||
ApolloAccountUpdateParams,
|
||||
ApolloAccountUpdateResponse
|
||||
> = {
|
||||
id: 'apollo_account_update',
|
||||
name: 'Apollo Update Account',
|
||||
description: 'Update an existing account in your Apollo database',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key',
|
||||
},
|
||||
account_id: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'ID of the account to update (e.g., "acc_abc123")',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Company name (e.g., "Acme Corporation")',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Company domain (e.g., "acme.com")',
|
||||
},
|
||||
phone: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Company phone number',
|
||||
},
|
||||
owner_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo user ID of the account owner',
|
||||
},
|
||||
account_stage_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo ID for the account stage to assign this account to',
|
||||
},
|
||||
raw_address: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Corporate location (e.g., "San Francisco, CA, USA")',
|
||||
},
|
||||
typed_custom_fields: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Custom field values as { custom_field_id: value } map',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: ApolloAccountUpdateParams) =>
|
||||
`https://api.apollo.io/api/v1/accounts/${params.account_id.trim()}`,
|
||||
method: 'PATCH',
|
||||
headers: (params: ApolloAccountUpdateParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
body: (params: ApolloAccountUpdateParams) => {
|
||||
const body: Record<string, unknown> = {}
|
||||
if (params.name) body.name = params.name
|
||||
if (params.domain) body.domain = params.domain
|
||||
if (params.phone) body.phone = params.phone
|
||||
if (params.owner_id) body.owner_id = params.owner_id
|
||||
if (params.account_stage_id) body.account_stage_id = params.account_stage_id
|
||||
if (params.raw_address) body.raw_address = params.raw_address
|
||||
if (params.typed_custom_fields) body.typed_custom_fields = params.typed_custom_fields
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
const account = data.account ?? (data.id ? data : null)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
account,
|
||||
updated: !!account,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
account: { type: 'json', description: 'Updated account data from Apollo', optional: true },
|
||||
updated: { type: 'boolean', description: 'Whether the account was successfully updated' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import type {
|
||||
ApolloContactBulkCreateParams,
|
||||
ApolloContactBulkCreateResponse,
|
||||
} from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloContactBulkCreateTool: ToolConfig<
|
||||
ApolloContactBulkCreateParams,
|
||||
ApolloContactBulkCreateResponse
|
||||
> = {
|
||||
id: 'apollo_contact_bulk_create',
|
||||
name: 'Apollo Bulk Create Contacts',
|
||||
description:
|
||||
'Create up to 100 contacts at once in your Apollo database. Supports deduplication to prevent creating duplicate contacts. Master key required.',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key (master key required)',
|
||||
},
|
||||
contacts: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Array of contacts to create (max 100). Each contact may include first_name, last_name, email, title, organization_name, account_id, owner_id, contact_stage_id, linkedin_url, phone (single string) or phone_numbers (array of {raw_number, position}), contact_emails, typed_custom_fields, and CRM IDs (salesforce_contact_id, hubspot_id, team_id) for cross-system matching',
|
||||
},
|
||||
append_label_names: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Label names to add to all contacts in this request (e.g., ["Hot Lead"])',
|
||||
},
|
||||
run_dedupe: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description:
|
||||
'Enable deduplication to prevent creating duplicate contacts. When true, existing contacts are returned without modification',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.apollo.io/api/v1/contacts/bulk_create',
|
||||
method: 'POST',
|
||||
headers: (params: ApolloContactBulkCreateParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
body: (params: ApolloContactBulkCreateParams) => {
|
||||
const body: Record<string, unknown> = {
|
||||
contacts: params.contacts.slice(0, 100),
|
||||
}
|
||||
if (params.run_dedupe !== undefined) {
|
||||
body.run_dedupe = params.run_dedupe
|
||||
}
|
||||
if (params.append_label_names && params.append_label_names.length > 0) {
|
||||
body.append_label_names = params.append_label_names
|
||||
}
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
const createdContacts = data.created_contacts || data.contacts || []
|
||||
const existingContacts = data.existing_contacts || []
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
created_contacts: createdContacts,
|
||||
existing_contacts: existingContacts,
|
||||
total_submitted: createdContacts.length + existingContacts.length,
|
||||
created: createdContacts.length,
|
||||
existing: existingContacts.length,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
created_contacts: {
|
||||
type: 'json',
|
||||
description: 'Array of newly created contacts',
|
||||
},
|
||||
existing_contacts: {
|
||||
type: 'json',
|
||||
description: 'Array of existing contacts (when deduplication is enabled)',
|
||||
},
|
||||
total_submitted: {
|
||||
type: 'number',
|
||||
description: 'Total number of contacts submitted',
|
||||
},
|
||||
created: {
|
||||
type: 'number',
|
||||
description: 'Number of contacts successfully created',
|
||||
},
|
||||
existing: {
|
||||
type: 'number',
|
||||
description: 'Number of existing contacts found',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
import type {
|
||||
ApolloContactBulkUpdateParams,
|
||||
ApolloContactBulkUpdateResponse,
|
||||
} from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloContactBulkUpdateTool: ToolConfig<
|
||||
ApolloContactBulkUpdateParams,
|
||||
ApolloContactBulkUpdateResponse
|
||||
> = {
|
||||
id: 'apollo_contact_bulk_update',
|
||||
name: 'Apollo Bulk Update Contacts',
|
||||
description:
|
||||
'Update up to 100 existing contacts at once in your Apollo database. Each contact must include an id field. Master key required.',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key (master key required)',
|
||||
},
|
||||
contact_ids: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Array of contact IDs to update. Must be paired with an object-form contact_attributes specifying the fields to apply uniformly to all listed contacts.',
|
||||
},
|
||||
contact_attributes: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Required. Either an array of per-contact updates (each with id) — used standalone — or a single object of attributes to apply to all contact_ids. Supported fields: owner_id, email, organization_name, title, first_name, last_name, account_id, present_raw_address, linkedin_url, typed_custom_fields',
|
||||
},
|
||||
async: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Force asynchronous processing. Automatically enabled for >100 contacts',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.apollo.io/api/v1/contacts/bulk_update',
|
||||
method: 'POST',
|
||||
headers: (params: ApolloContactBulkUpdateParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
body: (params: ApolloContactBulkUpdateParams) => {
|
||||
const body: Record<string, unknown> = {}
|
||||
if (params.contact_ids && params.contact_ids.length > 0) {
|
||||
body.contact_ids = params.contact_ids.slice(0, 100)
|
||||
}
|
||||
if (params.contact_attributes) {
|
||||
if (Array.isArray(params.contact_attributes)) {
|
||||
if (params.contact_attributes.length > 0) {
|
||||
body.contact_attributes = params.contact_attributes.slice(0, 100)
|
||||
}
|
||||
} else if (
|
||||
typeof params.contact_attributes === 'object' &&
|
||||
Object.keys(params.contact_attributes).length > 0
|
||||
) {
|
||||
body.contact_attributes = params.contact_attributes
|
||||
}
|
||||
}
|
||||
if (!body.contact_attributes) {
|
||||
throw new Error(
|
||||
'Apollo bulk update requires contact_attributes (the fields to update). Use contact_attributes alone (array of per-contact updates with id) or together with contact_ids (single object applied to all listed contacts).'
|
||||
)
|
||||
}
|
||||
if (!Array.isArray(body.contact_attributes) && !body.contact_ids) {
|
||||
throw new Error(
|
||||
'Apollo bulk update with object-form contact_attributes requires contact_ids to identify which contacts to update.'
|
||||
)
|
||||
}
|
||||
if (body.contact_ids && Array.isArray(body.contact_attributes)) {
|
||||
throw new Error(
|
||||
'Apollo contact bulk update cannot combine contact_ids with array-form contact_attributes. Use contact_ids with object-form contact_attributes for uniform updates, or use array-form contact_attributes alone (each entry carries its own id).'
|
||||
)
|
||||
}
|
||||
if (params.async !== undefined) body.async = params.async
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
const contacts = Array.isArray(data?.contacts) ? data.contacts : []
|
||||
const entityProgressJob = data?.entity_progress_job ?? null
|
||||
const jobId =
|
||||
typeof data?.job_id === 'string'
|
||||
? data.job_id
|
||||
: typeof entityProgressJob?.id === 'string'
|
||||
? entityProgressJob.id
|
||||
: null
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
contacts,
|
||||
entity_progress_job: entityProgressJob,
|
||||
job_id: jobId,
|
||||
message: data?.message ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
contacts: {
|
||||
type: 'json',
|
||||
description: 'Updated contacts (synchronous response, ≤100 contacts)',
|
||||
},
|
||||
entity_progress_job: {
|
||||
type: 'json',
|
||||
description: 'Async job descriptor (>100 contacts or async=true): {id, status, ...}',
|
||||
optional: true,
|
||||
},
|
||||
job_id: {
|
||||
type: 'string',
|
||||
description: 'Async job ID extracted from entity_progress_job',
|
||||
optional: true,
|
||||
},
|
||||
message: {
|
||||
type: 'string',
|
||||
description: 'Optional confirmation message from Apollo',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
import type { ApolloContactCreateParams, ApolloContactCreateResponse } from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloContactCreateTool: ToolConfig<
|
||||
ApolloContactCreateParams,
|
||||
ApolloContactCreateResponse
|
||||
> = {
|
||||
id: 'apollo_contact_create',
|
||||
name: 'Apollo Create Contact',
|
||||
description: 'Create a new contact in your Apollo database',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key',
|
||||
},
|
||||
first_name: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'First name of the contact',
|
||||
},
|
||||
last_name: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Last name of the contact',
|
||||
},
|
||||
email: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Email address of the contact',
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Job title (e.g., "VP of Sales", "Software Engineer")',
|
||||
},
|
||||
account_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Apollo account ID to associate with (e.g., "acc_abc123")',
|
||||
},
|
||||
owner_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description:
|
||||
'User ID of the contact owner (accepted by Apollo but not officially documented for POST /contacts)',
|
||||
},
|
||||
organization_name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Name of the contact\'s employer (e.g., "Apollo")',
|
||||
},
|
||||
website_url: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Corporate website URL (e.g., "https://www.apollo.io/")',
|
||||
},
|
||||
label_names: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lists/labels to add the contact to (e.g., ["Prospects"])',
|
||||
},
|
||||
contact_stage_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Apollo ID for the contact stage',
|
||||
},
|
||||
present_raw_address: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Personal location for the contact (e.g., "Atlanta, United States")',
|
||||
},
|
||||
direct_phone: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Primary phone number',
|
||||
},
|
||||
corporate_phone: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Work/office phone number',
|
||||
},
|
||||
mobile_phone: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Mobile phone number',
|
||||
},
|
||||
home_phone: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Home phone number',
|
||||
},
|
||||
other_phone: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Alternative phone number',
|
||||
},
|
||||
typed_custom_fields: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Custom field values keyed by custom field ID',
|
||||
},
|
||||
run_dedupe: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'When true, Apollo deduplicates against existing contacts',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.apollo.io/api/v1/contacts',
|
||||
method: 'POST',
|
||||
headers: (params: ApolloContactCreateParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
body: (params: ApolloContactCreateParams) => {
|
||||
const body: Record<string, unknown> = {
|
||||
first_name: params.first_name,
|
||||
last_name: params.last_name,
|
||||
}
|
||||
if (params.email) body.email = params.email
|
||||
if (params.title) body.title = params.title
|
||||
if (params.account_id) body.account_id = params.account_id
|
||||
if (params.owner_id) body.owner_id = params.owner_id
|
||||
if (params.organization_name) body.organization_name = params.organization_name
|
||||
if (params.website_url) body.website_url = params.website_url
|
||||
if (params.label_names && params.label_names.length > 0) {
|
||||
body.label_names = params.label_names
|
||||
}
|
||||
if (params.contact_stage_id) body.contact_stage_id = params.contact_stage_id
|
||||
if (params.present_raw_address) body.present_raw_address = params.present_raw_address
|
||||
if (params.direct_phone) body.direct_phone = params.direct_phone
|
||||
if (params.corporate_phone) body.corporate_phone = params.corporate_phone
|
||||
if (params.mobile_phone) body.mobile_phone = params.mobile_phone
|
||||
if (params.home_phone) body.home_phone = params.home_phone
|
||||
if (params.other_phone) body.other_phone = params.other_phone
|
||||
if (params.typed_custom_fields) body.typed_custom_fields = params.typed_custom_fields
|
||||
if (params.run_dedupe !== undefined) body.run_dedupe = params.run_dedupe
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
const contact = data?.contact ?? (data?.id ? data : null)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
contact,
|
||||
created: !!contact,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
contact: { type: 'json', description: 'Created contact data from Apollo', optional: true },
|
||||
created: { type: 'boolean', description: 'Whether the contact was successfully created' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
import type { ApolloContactSearchParams, ApolloContactSearchResponse } from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloContactSearchTool: ToolConfig<
|
||||
ApolloContactSearchParams,
|
||||
ApolloContactSearchResponse
|
||||
> = {
|
||||
id: 'apollo_contact_search',
|
||||
name: 'Apollo Search Contacts',
|
||||
description: "Search your team's contacts in Apollo",
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key',
|
||||
},
|
||||
q_keywords: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Keywords to search for',
|
||||
},
|
||||
contact_stage_ids: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Filter by contact stage IDs',
|
||||
},
|
||||
contact_label_ids: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Filter by Apollo label IDs (lists)',
|
||||
},
|
||||
sort_by_field: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description:
|
||||
'Sort field: contact_last_activity_date, contact_email_last_opened_at, contact_email_last_clicked_at, contact_created_at, or contact_updated_at',
|
||||
},
|
||||
sort_ascending: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'When true, sort ascending. Must be used together with sort_by_field',
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number for pagination (e.g., 1, 2, 3)',
|
||||
},
|
||||
per_page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page, max 100 (e.g., 25, 50, 100)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.apollo.io/api/v1/contacts/search',
|
||||
method: 'POST',
|
||||
headers: (params: ApolloContactSearchParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
body: (params: ApolloContactSearchParams) => {
|
||||
const body: Record<string, unknown> = {
|
||||
page: params.page || 1,
|
||||
per_page: Math.min(params.per_page || 25, 100),
|
||||
}
|
||||
if (params.q_keywords) body.q_keywords = params.q_keywords
|
||||
if (params.contact_stage_ids?.length) {
|
||||
body.contact_stage_ids = params.contact_stage_ids
|
||||
}
|
||||
if (params.contact_label_ids?.length) {
|
||||
body.contact_label_ids = params.contact_label_ids
|
||||
}
|
||||
if (params.sort_by_field) body.sort_by_field = params.sort_by_field
|
||||
if (params.sort_ascending !== undefined) body.sort_ascending = params.sort_ascending
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
contacts: data.contacts ?? [],
|
||||
pagination: data.pagination ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
contacts: {
|
||||
type: 'json',
|
||||
description: 'Array of contacts matching the search criteria',
|
||||
},
|
||||
pagination: { type: 'json', description: 'Pagination information', optional: true },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
import type { ApolloContactUpdateParams, ApolloContactUpdateResponse } from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloContactUpdateTool: ToolConfig<
|
||||
ApolloContactUpdateParams,
|
||||
ApolloContactUpdateResponse
|
||||
> = {
|
||||
id: 'apollo_contact_update',
|
||||
name: 'Apollo Update Contact',
|
||||
description: 'Update an existing contact in your Apollo database',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key',
|
||||
},
|
||||
contact_id: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'ID of the contact to update (e.g., "con_abc123")',
|
||||
},
|
||||
first_name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'First name of the contact',
|
||||
},
|
||||
last_name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Last name of the contact',
|
||||
},
|
||||
email: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Email address',
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Job title (e.g., "VP of Sales", "Software Engineer")',
|
||||
},
|
||||
account_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Apollo account ID (e.g., "acc_abc123")',
|
||||
},
|
||||
owner_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description:
|
||||
'User ID of the contact owner (accepted by Apollo but not officially documented for PATCH /contacts/{id})',
|
||||
},
|
||||
organization_name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Name of the contact\'s employer (e.g., "Apollo")',
|
||||
},
|
||||
website_url: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Corporate website URL (e.g., "https://www.apollo.io/")',
|
||||
},
|
||||
label_names: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Lists/labels to add the contact to (e.g., ["Prospects"])',
|
||||
},
|
||||
contact_stage_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Apollo ID for the contact stage',
|
||||
},
|
||||
present_raw_address: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Personal location for the contact (e.g., "Atlanta, United States")',
|
||||
},
|
||||
direct_phone: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Primary phone number',
|
||||
},
|
||||
corporate_phone: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Work/office phone number',
|
||||
},
|
||||
mobile_phone: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Mobile phone number',
|
||||
},
|
||||
home_phone: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Home phone number',
|
||||
},
|
||||
other_phone: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Alternative phone number',
|
||||
},
|
||||
typed_custom_fields: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Custom field values keyed by custom field ID',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: ApolloContactUpdateParams) =>
|
||||
`https://api.apollo.io/api/v1/contacts/${params.contact_id.trim()}`,
|
||||
method: 'PATCH',
|
||||
headers: (params: ApolloContactUpdateParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
body: (params: ApolloContactUpdateParams) => {
|
||||
const body: Record<string, unknown> = {}
|
||||
if (params.first_name) body.first_name = params.first_name
|
||||
if (params.last_name) body.last_name = params.last_name
|
||||
if (params.email) body.email = params.email
|
||||
if (params.title) body.title = params.title
|
||||
if (params.account_id) body.account_id = params.account_id
|
||||
if (params.owner_id) body.owner_id = params.owner_id
|
||||
if (params.organization_name) body.organization_name = params.organization_name
|
||||
if (params.website_url) body.website_url = params.website_url
|
||||
if (params.label_names && params.label_names.length > 0) {
|
||||
body.label_names = params.label_names
|
||||
}
|
||||
if (params.contact_stage_id) body.contact_stage_id = params.contact_stage_id
|
||||
if (params.present_raw_address) body.present_raw_address = params.present_raw_address
|
||||
if (params.direct_phone) body.direct_phone = params.direct_phone
|
||||
if (params.corporate_phone) body.corporate_phone = params.corporate_phone
|
||||
if (params.mobile_phone) body.mobile_phone = params.mobile_phone
|
||||
if (params.home_phone) body.home_phone = params.home_phone
|
||||
if (params.other_phone) body.other_phone = params.other_phone
|
||||
if (params.typed_custom_fields) body.typed_custom_fields = params.typed_custom_fields
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
const contact = data?.contact ?? (data?.id ? data : null)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
contact,
|
||||
updated: !!contact,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
contact: { type: 'json', description: 'Updated contact data from Apollo', optional: true },
|
||||
updated: { type: 'boolean', description: 'Whether the contact was successfully updated' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import type { ApolloEmailAccountsParams, ApolloEmailAccountsResponse } from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloEmailAccountsTool: ToolConfig<
|
||||
ApolloEmailAccountsParams,
|
||||
ApolloEmailAccountsResponse
|
||||
> = {
|
||||
id: 'apollo_email_accounts',
|
||||
name: 'Apollo Get Email Accounts',
|
||||
description: "Get list of team's linked email accounts in Apollo",
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key (master key required)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.apollo.io/api/v1/email_accounts',
|
||||
method: 'GET',
|
||||
headers: (params: ApolloEmailAccountsParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
const accounts = Array.isArray(data) ? data : data.email_accounts || data.data || []
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
email_accounts: accounts,
|
||||
total: accounts.length,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
email_accounts: { type: 'json', description: 'Array of team email accounts linked in Apollo' },
|
||||
total: { type: 'number', description: 'Total count of email accounts' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
export { apolloAccountBulkCreateTool } from './account_bulk_create'
|
||||
export { apolloAccountBulkUpdateTool } from './account_bulk_update'
|
||||
export { apolloAccountCreateTool } from './account_create'
|
||||
export { apolloAccountSearchTool } from './account_search'
|
||||
export { apolloAccountUpdateTool } from './account_update'
|
||||
export { apolloContactBulkCreateTool } from './contact_bulk_create'
|
||||
export { apolloContactBulkUpdateTool } from './contact_bulk_update'
|
||||
export { apolloContactCreateTool } from './contact_create'
|
||||
export { apolloContactSearchTool } from './contact_search'
|
||||
export { apolloContactUpdateTool } from './contact_update'
|
||||
export { apolloEmailAccountsTool } from './email_accounts'
|
||||
export { apolloOpportunityCreateTool } from './opportunity_create'
|
||||
export { apolloOpportunityGetTool } from './opportunity_get'
|
||||
export { apolloOpportunitySearchTool } from './opportunity_search'
|
||||
export { apolloOpportunityUpdateTool } from './opportunity_update'
|
||||
export { apolloOrganizationBulkEnrichTool } from './organization_bulk_enrich'
|
||||
export { apolloOrganizationEnrichTool } from './organization_enrich'
|
||||
export { apolloOrganizationSearchTool } from './organization_search'
|
||||
export { apolloPeopleBulkEnrichTool } from './people_bulk_enrich'
|
||||
export { apolloPeopleEnrichTool } from './people_enrich'
|
||||
export { apolloPeopleSearchTool } from './people_search'
|
||||
export { apolloSequenceAddContactsTool } from './sequence_add_contacts'
|
||||
export { apolloSequenceSearchTool } from './sequence_search'
|
||||
export { apolloTaskCreateTool } from './task_create'
|
||||
export { apolloTaskSearchTool } from './task_search'
|
||||
export type * from './types'
|
||||
@@ -0,0 +1,115 @@
|
||||
import type {
|
||||
ApolloOpportunityCreateParams,
|
||||
ApolloOpportunityCreateResponse,
|
||||
} from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloOpportunityCreateTool: ToolConfig<
|
||||
ApolloOpportunityCreateParams,
|
||||
ApolloOpportunityCreateResponse
|
||||
> = {
|
||||
id: 'apollo_opportunity_create',
|
||||
name: 'Apollo Create Opportunity',
|
||||
description: 'Create a new deal for an account in your Apollo database (master key required)',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key (master key required)',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Name of the opportunity/deal (e.g., "Enterprise License - Q1")',
|
||||
},
|
||||
account_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'ID of the account this opportunity belongs to (e.g., "acc_abc123")',
|
||||
},
|
||||
amount: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Monetary value as a plain number string with no commas or currency symbols',
|
||||
},
|
||||
opportunity_stage_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'ID of the opportunity stage',
|
||||
},
|
||||
owner_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'User ID of the opportunity owner',
|
||||
},
|
||||
closed_date: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Expected close date in YYYY-MM-DD format',
|
||||
},
|
||||
typed_custom_fields: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Custom field values as { custom_field_id: value } map',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.apollo.io/api/v1/opportunities',
|
||||
method: 'POST',
|
||||
headers: (params: ApolloOpportunityCreateParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
body: (params: ApolloOpportunityCreateParams) => {
|
||||
const body: Record<string, unknown> = { name: params.name }
|
||||
if (params.account_id) body.account_id = params.account_id
|
||||
if (params.amount !== undefined && params.amount !== null && params.amount !== '') {
|
||||
body.amount = String(params.amount)
|
||||
}
|
||||
if (params.opportunity_stage_id) body.opportunity_stage_id = params.opportunity_stage_id
|
||||
if (params.owner_id) body.owner_id = params.owner_id
|
||||
if (params.closed_date) body.closed_date = params.closed_date
|
||||
if (params.typed_custom_fields) body.typed_custom_fields = params.typed_custom_fields
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
const opportunity = data.opportunity ?? (data.id ? data : null)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
opportunity,
|
||||
created: !!opportunity,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
opportunity: {
|
||||
type: 'json',
|
||||
description: 'Created opportunity data from Apollo',
|
||||
optional: true,
|
||||
},
|
||||
created: { type: 'boolean', description: 'Whether the opportunity was successfully created' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import type { ApolloOpportunityGetParams, ApolloOpportunityGetResponse } from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloOpportunityGetTool: ToolConfig<
|
||||
ApolloOpportunityGetParams,
|
||||
ApolloOpportunityGetResponse
|
||||
> = {
|
||||
id: 'apollo_opportunity_get',
|
||||
name: 'Apollo Get Opportunity',
|
||||
description: 'Retrieve complete details of a specific deal/opportunity by ID',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key',
|
||||
},
|
||||
opportunity_id: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'ID of the opportunity to retrieve (e.g., "opp_abc123")',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: ApolloOpportunityGetParams) =>
|
||||
`https://api.apollo.io/api/v1/opportunities/${params.opportunity_id.trim()}`,
|
||||
method: 'GET',
|
||||
headers: (params: ApolloOpportunityGetParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
opportunity: data.opportunity ?? null,
|
||||
found: !!data.opportunity,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
opportunity: {
|
||||
type: 'json',
|
||||
description: 'Complete opportunity data from Apollo',
|
||||
optional: true,
|
||||
},
|
||||
found: { type: 'boolean', description: 'Whether the opportunity was found' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import type {
|
||||
ApolloOpportunitySearchParams,
|
||||
ApolloOpportunitySearchResponse,
|
||||
} from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloOpportunitySearchTool: ToolConfig<
|
||||
ApolloOpportunitySearchParams,
|
||||
ApolloOpportunitySearchResponse
|
||||
> = {
|
||||
id: 'apollo_opportunity_search',
|
||||
name: 'Apollo Search Opportunities',
|
||||
description: "Search and list all deals/opportunities in your team's Apollo account",
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key',
|
||||
},
|
||||
sort_by_field: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort field: "amount", "is_closed", or "is_won"',
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number for pagination (e.g., 1, 2, 3)',
|
||||
},
|
||||
per_page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page, max 100 (e.g., 25, 50, 100)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: ApolloOpportunitySearchParams) => {
|
||||
const query = new URLSearchParams()
|
||||
query.set('page', String(params.page || 1))
|
||||
query.set('per_page', String(Math.min(params.per_page || 25, 100)))
|
||||
if (params.sort_by_field) query.set('sort_by_field', params.sort_by_field)
|
||||
return `https://api.apollo.io/api/v1/opportunities/search?${query.toString()}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: ApolloOpportunitySearchParams) => ({
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
opportunities: data.opportunities ?? [],
|
||||
page: data.pagination?.page ?? 1,
|
||||
per_page: data.pagination?.per_page ?? 25,
|
||||
total_entries: data.pagination?.total_entries ?? 0,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
opportunities: {
|
||||
type: 'json',
|
||||
description: 'Array of opportunities matching the search criteria',
|
||||
},
|
||||
page: { type: 'number', description: 'Current page number' },
|
||||
per_page: { type: 'number', description: 'Results per page' },
|
||||
total_entries: { type: 'number', description: 'Total matching entries' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
import type {
|
||||
ApolloOpportunityUpdateParams,
|
||||
ApolloOpportunityUpdateResponse,
|
||||
} from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloOpportunityUpdateTool: ToolConfig<
|
||||
ApolloOpportunityUpdateParams,
|
||||
ApolloOpportunityUpdateResponse
|
||||
> = {
|
||||
id: 'apollo_opportunity_update',
|
||||
name: 'Apollo Update Opportunity',
|
||||
description: 'Update an existing deal/opportunity in your Apollo database',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key',
|
||||
},
|
||||
opportunity_id: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'ID of the opportunity to update (e.g., "opp_abc123")',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Name of the opportunity/deal (e.g., "Enterprise License - Q1")',
|
||||
},
|
||||
amount: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Monetary value as a plain number string with no commas or currency symbols',
|
||||
},
|
||||
opportunity_stage_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'ID of the opportunity stage',
|
||||
},
|
||||
owner_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'User ID of the opportunity owner',
|
||||
},
|
||||
closed_date: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Expected close date in YYYY-MM-DD format',
|
||||
},
|
||||
typed_custom_fields: {
|
||||
type: 'json',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Custom field values as { custom_field_id: value } map',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: ApolloOpportunityUpdateParams) =>
|
||||
`https://api.apollo.io/api/v1/opportunities/${params.opportunity_id.trim()}`,
|
||||
method: 'PATCH',
|
||||
headers: (params: ApolloOpportunityUpdateParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
body: (params: ApolloOpportunityUpdateParams) => {
|
||||
const body: Record<string, unknown> = {}
|
||||
if (params.name) body.name = params.name
|
||||
if (params.amount !== undefined && params.amount !== null && params.amount !== '') {
|
||||
body.amount = String(params.amount)
|
||||
}
|
||||
if (params.opportunity_stage_id) body.opportunity_stage_id = params.opportunity_stage_id
|
||||
if (params.owner_id) body.owner_id = params.owner_id
|
||||
if (params.closed_date) body.closed_date = params.closed_date
|
||||
if (params.typed_custom_fields) body.typed_custom_fields = params.typed_custom_fields
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
const opportunity = data.opportunity ?? (data.id ? data : null)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
opportunity,
|
||||
updated: !!opportunity,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
opportunity: {
|
||||
type: 'json',
|
||||
description: 'Updated opportunity data from Apollo',
|
||||
optional: true,
|
||||
},
|
||||
updated: { type: 'boolean', description: 'Whether the opportunity was successfully updated' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import type {
|
||||
ApolloOrganizationBulkEnrichParams,
|
||||
ApolloOrganizationBulkEnrichResponse,
|
||||
} from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloOrganizationBulkEnrichTool: ToolConfig<
|
||||
ApolloOrganizationBulkEnrichParams,
|
||||
ApolloOrganizationBulkEnrichResponse
|
||||
> = {
|
||||
id: 'apollo_organization_bulk_enrich',
|
||||
name: 'Apollo Bulk Organization Enrichment',
|
||||
description: 'Enrich data for up to 10 organizations at once using Apollo',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key',
|
||||
},
|
||||
domains: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Array of company domains to enrich (max 10, no www. or @, e.g., ["apollo.io", "stripe.com"])',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: ApolloOrganizationBulkEnrichParams) => {
|
||||
const qs = new URLSearchParams()
|
||||
for (const domain of params.domains.slice(0, 10)) {
|
||||
const trimmed = typeof domain === 'string' ? domain.trim() : ''
|
||||
if (trimmed) qs.append('domains[]', trimmed)
|
||||
}
|
||||
return `https://api.apollo.io/api/v1/organizations/bulk_enrich?${qs.toString()}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: ApolloOrganizationBulkEnrichParams) => ({
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
const organizations = data.organizations ?? []
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
organizations,
|
||||
total: data.total_requested_domains ?? organizations.length,
|
||||
enriched: data.unique_enriched_records ?? organizations.length,
|
||||
missing_records: data.missing_records ?? 0,
|
||||
unique_domains: data.unique_domains ?? organizations.length,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
organizations: { type: 'json', description: 'Array of enriched organization data' },
|
||||
total: { type: 'number', description: 'Total number of domains requested' },
|
||||
enriched: { type: 'number', description: 'Number of unique enriched records' },
|
||||
missing_records: {
|
||||
type: 'number',
|
||||
description: 'Number of domains that could not be enriched',
|
||||
},
|
||||
unique_domains: { type: 'number', description: 'Number of unique domains processed' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import type {
|
||||
ApolloOrganizationEnrichParams,
|
||||
ApolloOrganizationEnrichResponse,
|
||||
} from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloOrganizationEnrichTool: ToolConfig<
|
||||
ApolloOrganizationEnrichParams,
|
||||
ApolloOrganizationEnrichResponse
|
||||
> = {
|
||||
id: 'apollo_organization_enrich',
|
||||
name: 'Apollo Organization Enrichment',
|
||||
description: 'Enrich data for a single organization using Apollo',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Company domain (e.g., "apollo.io", "acme.com")',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: ApolloOrganizationEnrichParams) => {
|
||||
const domain = params.domain?.trim()
|
||||
if (!domain) {
|
||||
throw new Error('domain is required for organization enrichment')
|
||||
}
|
||||
const qs = new URLSearchParams({ domain })
|
||||
return `https://api.apollo.io/api/v1/organizations/enrich?${qs.toString()}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: ApolloOrganizationEnrichParams) => ({
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
organization: data.organization ?? null,
|
||||
enriched: !!data.organization,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
organization: {
|
||||
type: 'json',
|
||||
description: 'Enriched organization data from Apollo',
|
||||
optional: true,
|
||||
},
|
||||
enriched: {
|
||||
type: 'boolean',
|
||||
description: 'Whether the organization was successfully enriched',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
import type {
|
||||
ApolloOrganizationSearchParams,
|
||||
ApolloOrganizationSearchResponse,
|
||||
} from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloOrganizationSearchTool: ToolConfig<
|
||||
ApolloOrganizationSearchParams,
|
||||
ApolloOrganizationSearchResponse
|
||||
> = {
|
||||
id: 'apollo_organization_search',
|
||||
name: 'Apollo Organization Search',
|
||||
description: "Search Apollo's database for companies using filters",
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key',
|
||||
},
|
||||
organization_locations: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Company HQ locations (cities, US states, or countries)',
|
||||
},
|
||||
organization_not_locations: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Exclude companies whose HQ is in these locations',
|
||||
},
|
||||
organization_num_employees_ranges: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Employee count ranges as "min,max" strings (e.g., ["1,10", "250,500", "10000,20000"])',
|
||||
},
|
||||
q_organization_keyword_tags: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Industry or keyword tags',
|
||||
},
|
||||
q_organization_name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Organization name to search for (e.g., "Acme", "TechCorp")',
|
||||
},
|
||||
organization_ids: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Apollo organization IDs to include (e.g., ["5e66b6381e05b4008c8331b8"])',
|
||||
},
|
||||
q_organization_domains_list: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Domain names to filter by (no www. or @, up to 1,000)',
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number for pagination (e.g., 1, 2, 3)',
|
||||
},
|
||||
per_page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page, max 100 (e.g., 25, 50, 100)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: ApolloOrganizationSearchParams) => {
|
||||
const qs = new URLSearchParams()
|
||||
qs.set('page', String(params.page || 1))
|
||||
qs.set('per_page', String(Math.min(params.per_page || 25, 100)))
|
||||
|
||||
const appendArray = (key: string, values?: string[]) => {
|
||||
if (!values?.length) return
|
||||
for (const v of values) {
|
||||
if (typeof v === 'string' && v) qs.append(`${key}[]`, v)
|
||||
}
|
||||
}
|
||||
appendArray('organization_locations', params.organization_locations)
|
||||
appendArray('organization_not_locations', params.organization_not_locations)
|
||||
appendArray('organization_num_employees_ranges', params.organization_num_employees_ranges)
|
||||
appendArray('q_organization_keyword_tags', params.q_organization_keyword_tags)
|
||||
appendArray('organization_ids', params.organization_ids)
|
||||
appendArray('q_organization_domains_list', params.q_organization_domains_list)
|
||||
if (params.q_organization_name) qs.set('q_organization_name', params.q_organization_name)
|
||||
|
||||
return `https://api.apollo.io/api/v1/mixed_companies/search?${qs.toString()}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: ApolloOrganizationSearchParams) => ({
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
organizations: data.organizations || [],
|
||||
page: data.pagination?.page || 1,
|
||||
per_page: data.pagination?.per_page || 25,
|
||||
total_entries: data.pagination?.total_entries || 0,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
organizations: {
|
||||
type: 'json',
|
||||
description: 'Array of organizations matching the search criteria',
|
||||
},
|
||||
page: { type: 'number', description: 'Current page number' },
|
||||
per_page: { type: 'number', description: 'Results per page' },
|
||||
total_entries: { type: 'number', description: 'Total matching entries' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
import type {
|
||||
ApolloPeopleBulkEnrichParams,
|
||||
ApolloPeopleBulkEnrichResponse,
|
||||
} from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloPeopleBulkEnrichTool: ToolConfig<
|
||||
ApolloPeopleBulkEnrichParams,
|
||||
ApolloPeopleBulkEnrichResponse
|
||||
> = {
|
||||
id: 'apollo_people_bulk_enrich',
|
||||
name: 'Apollo Bulk People Enrichment',
|
||||
description: 'Enrich data for up to 10 people at once using Apollo',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key',
|
||||
},
|
||||
people: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Array of people to enrich (max 10)',
|
||||
},
|
||||
reveal_personal_emails: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Reveal personal email addresses (uses credits)',
|
||||
},
|
||||
reveal_phone_number: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Reveal phone numbers (uses credits, requires webhook_url)',
|
||||
},
|
||||
webhook_url: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description:
|
||||
'Webhook URL for async phone number delivery (required when reveal_phone_number is true)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: ApolloPeopleBulkEnrichParams) => {
|
||||
const qs = new URLSearchParams()
|
||||
if (params.reveal_personal_emails !== undefined) {
|
||||
qs.set('reveal_personal_emails', String(params.reveal_personal_emails))
|
||||
}
|
||||
if (params.reveal_phone_number !== undefined) {
|
||||
qs.set('reveal_phone_number', String(params.reveal_phone_number))
|
||||
}
|
||||
if (params.webhook_url) {
|
||||
qs.set('webhook_url', params.webhook_url)
|
||||
}
|
||||
const query = qs.toString()
|
||||
return `https://api.apollo.io/api/v1/people/bulk_match${query ? `?${query}` : ''}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: ApolloPeopleBulkEnrichParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
body: (params: ApolloPeopleBulkEnrichParams) => ({
|
||||
details: params.people.slice(0, 10),
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
const matches = Array.isArray(data.matches)
|
||||
? data.matches
|
||||
: Array.isArray(data.people)
|
||||
? data.people
|
||||
: []
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
matches,
|
||||
total_requested_enrichments: data.total_requested_enrichments ?? matches.length,
|
||||
unique_enriched_records: data.unique_enriched_records ?? matches.filter(Boolean).length,
|
||||
missing_records: data.missing_records ?? null,
|
||||
credits_consumed: data.credits_consumed ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
matches: {
|
||||
type: 'json',
|
||||
description: 'Array of enriched people (null entries indicate no match)',
|
||||
},
|
||||
total_requested_enrichments: {
|
||||
type: 'number',
|
||||
description: 'Total number of records submitted for enrichment',
|
||||
},
|
||||
unique_enriched_records: {
|
||||
type: 'number',
|
||||
description: 'Number of records successfully enriched',
|
||||
},
|
||||
missing_records: {
|
||||
type: 'number',
|
||||
description: 'Number of records that could not be enriched',
|
||||
optional: true,
|
||||
},
|
||||
credits_consumed: {
|
||||
type: 'number',
|
||||
description: 'Number of Apollo credits consumed by this request',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
import type { ApolloPeopleEnrichParams, ApolloPeopleEnrichResponse } from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloPeopleEnrichTool: ToolConfig<
|
||||
ApolloPeopleEnrichParams,
|
||||
ApolloPeopleEnrichResponse
|
||||
> = {
|
||||
id: 'apollo_people_enrich',
|
||||
name: 'Apollo People Enrichment',
|
||||
description: 'Enrich data for a single person using Apollo',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key',
|
||||
},
|
||||
first_name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'First name of the person',
|
||||
},
|
||||
last_name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Last name of the person',
|
||||
},
|
||||
name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Full name of the person (alternative to first_name/last_name)',
|
||||
},
|
||||
id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Apollo ID for the person',
|
||||
},
|
||||
hashed_email: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'MD5 or SHA-256 hashed email',
|
||||
},
|
||||
email: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Email address of the person',
|
||||
},
|
||||
organization_name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Company name where the person works',
|
||||
},
|
||||
domain: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Company domain (e.g., "apollo.io", "acme.com")',
|
||||
},
|
||||
linkedin_url: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'LinkedIn profile URL',
|
||||
},
|
||||
reveal_personal_emails: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Reveal personal email addresses (uses credits)',
|
||||
},
|
||||
reveal_phone_number: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Reveal phone numbers (uses credits, requires webhook_url)',
|
||||
},
|
||||
webhook_url: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description:
|
||||
'Webhook URL for async phone number delivery (required when reveal_phone_number is true)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: ApolloPeopleEnrichParams) => {
|
||||
const qs = new URLSearchParams()
|
||||
if (params.first_name) qs.set('first_name', params.first_name)
|
||||
if (params.last_name) qs.set('last_name', params.last_name)
|
||||
if (params.name) qs.set('name', params.name)
|
||||
if (params.email) qs.set('email', params.email)
|
||||
if (params.hashed_email) qs.set('hashed_email', params.hashed_email)
|
||||
if (params.id) qs.set('id', params.id)
|
||||
if (params.organization_name) qs.set('organization_name', params.organization_name)
|
||||
if (params.domain) qs.set('domain', params.domain)
|
||||
if (params.linkedin_url) qs.set('linkedin_url', params.linkedin_url)
|
||||
if (params.reveal_personal_emails !== undefined) {
|
||||
qs.set('reveal_personal_emails', String(params.reveal_personal_emails))
|
||||
}
|
||||
if (params.reveal_phone_number !== undefined) {
|
||||
qs.set('reveal_phone_number', String(params.reveal_phone_number))
|
||||
}
|
||||
if (params.webhook_url) {
|
||||
qs.set('webhook_url', params.webhook_url)
|
||||
}
|
||||
const query = qs.toString()
|
||||
return `https://api.apollo.io/api/v1/people/match${query ? `?${query}` : ''}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: ApolloPeopleEnrichParams) => ({
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
person: data.person ?? null,
|
||||
enriched: !!data.person,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
person: {
|
||||
type: 'json',
|
||||
description: 'Enriched person data from Apollo',
|
||||
optional: true,
|
||||
},
|
||||
enriched: { type: 'boolean', description: 'Whether the person was successfully enriched' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
import type { ApolloPeopleSearchParams, ApolloPeopleSearchResponse } from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloPeopleSearchTool: ToolConfig<
|
||||
ApolloPeopleSearchParams,
|
||||
ApolloPeopleSearchResponse
|
||||
> = {
|
||||
id: 'apollo_people_search',
|
||||
name: 'Apollo People Search',
|
||||
description: "Search Apollo's database for people using demographic filters",
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key',
|
||||
},
|
||||
person_titles: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Job titles to search for (e.g., ["CEO", "VP of Sales"])',
|
||||
},
|
||||
include_similar_titles: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to return people with job titles similar to person_titles',
|
||||
},
|
||||
person_locations: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Locations to search in (e.g., ["San Francisco, CA", "New York, NY"])',
|
||||
},
|
||||
person_seniorities: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Seniority levels (one of: owner, founder, c_suite, partner, vp, head, director, manager, senior, entry, intern)',
|
||||
},
|
||||
organization_ids: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Apollo organization IDs to filter by (e.g., ["5e66b6381e05b4008c8331b8"])',
|
||||
},
|
||||
organization_names: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Company names to search within (legacy filter)',
|
||||
},
|
||||
organization_locations: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
"Headquarters locations of the people's current employer (e.g., ['texas', 'tokyo', 'spain'])",
|
||||
},
|
||||
q_organization_domains_list: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Employer domain names (e.g., ["apollo.io", "microsoft.com"]) — up to 1,000, no www. or @',
|
||||
},
|
||||
organization_num_employees_ranges: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Employee count ranges for the person\'s current employer. Each entry is "min,max" (e.g., ["1,10", "250,500", "10000,20000"])',
|
||||
},
|
||||
contact_email_status: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Email statuses to filter by: "verified", "unverified", "likely to engage", "unavailable"',
|
||||
},
|
||||
q_keywords: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Keywords to search for',
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number for pagination, default 1 (e.g., 1, 2, 3)',
|
||||
},
|
||||
per_page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page, default 25, max 100 (e.g., 25, 50, 100)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.apollo.io/api/v1/mixed_people/search',
|
||||
method: 'POST',
|
||||
headers: (params: ApolloPeopleSearchParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
body: (params: ApolloPeopleSearchParams) => {
|
||||
const body: Record<string, unknown> = {
|
||||
page: params.page || 1,
|
||||
per_page: Math.min(params.per_page || 25, 100),
|
||||
}
|
||||
|
||||
if (params.person_titles && params.person_titles.length > 0) {
|
||||
body.person_titles = params.person_titles
|
||||
}
|
||||
if (params.include_similar_titles !== undefined) {
|
||||
body.include_similar_titles = params.include_similar_titles
|
||||
}
|
||||
if (params.person_locations && params.person_locations.length > 0) {
|
||||
body.person_locations = params.person_locations
|
||||
}
|
||||
if (params.person_seniorities && params.person_seniorities.length > 0) {
|
||||
body.person_seniorities = params.person_seniorities
|
||||
}
|
||||
if (params.organization_ids && params.organization_ids.length > 0) {
|
||||
body.organization_ids = params.organization_ids
|
||||
}
|
||||
if (params.organization_names && params.organization_names.length > 0) {
|
||||
body.organization_names = params.organization_names
|
||||
}
|
||||
if (params.organization_locations && params.organization_locations.length > 0) {
|
||||
body.organization_locations = params.organization_locations
|
||||
}
|
||||
if (params.q_organization_domains_list && params.q_organization_domains_list.length > 0) {
|
||||
body.q_organization_domains_list = params.q_organization_domains_list
|
||||
}
|
||||
if (
|
||||
params.organization_num_employees_ranges &&
|
||||
params.organization_num_employees_ranges.length > 0
|
||||
) {
|
||||
body.organization_num_employees_ranges = params.organization_num_employees_ranges
|
||||
}
|
||||
if (params.contact_email_status && params.contact_email_status.length > 0) {
|
||||
body.contact_email_status = params.contact_email_status
|
||||
}
|
||||
if (params.q_keywords) {
|
||||
body.q_keywords = params.q_keywords
|
||||
}
|
||||
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
// The legacy /mixed_people/search endpoint nests pagination under `pagination`,
|
||||
// while api_search returns these top-level. Read both shapes defensively.
|
||||
const pagination = data.pagination ?? {}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
people: data.people || [],
|
||||
page: pagination.page ?? data.page ?? 1,
|
||||
per_page: pagination.per_page ?? data.per_page ?? 25,
|
||||
total_entries: pagination.total_entries ?? data.total_entries ?? 0,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
people: { type: 'json', description: 'Array of people matching the search criteria' },
|
||||
page: { type: 'number', description: 'Current page number' },
|
||||
per_page: { type: 'number', description: 'Results per page' },
|
||||
total_entries: { type: 'number', description: 'Total matching entries' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
import type {
|
||||
ApolloSequenceAddContactsParams,
|
||||
ApolloSequenceAddContactsResponse,
|
||||
} from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloSequenceAddContactsTool: ToolConfig<
|
||||
ApolloSequenceAddContactsParams,
|
||||
ApolloSequenceAddContactsResponse
|
||||
> = {
|
||||
id: 'apollo_sequence_add_contacts',
|
||||
name: 'Apollo Add Contacts to Sequence',
|
||||
description: 'Add contacts to an Apollo sequence',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key (master key required)',
|
||||
},
|
||||
sequence_id: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'ID of the sequence to add contacts to (e.g., "seq_abc123")',
|
||||
},
|
||||
contact_ids: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Array of contact IDs to add to the sequence (e.g., ["con_abc123", "con_def456"]). Either contact_ids or label_names must be provided.',
|
||||
},
|
||||
label_names: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Array of label names to identify contacts to add to the sequence. Either contact_ids or label_names must be provided.',
|
||||
},
|
||||
send_email_from_email_account_id: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'ID of the email account to send from. Use the Get Email Accounts operation to look this up.',
|
||||
},
|
||||
send_email_from_email_address: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Specific email address to send from within the email account.',
|
||||
},
|
||||
sequence_no_email: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Add contacts even if they have no email address',
|
||||
},
|
||||
sequence_unverified_email: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Add contacts with unverified email addresses',
|
||||
},
|
||||
sequence_job_change: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Add contacts who recently changed jobs',
|
||||
},
|
||||
sequence_active_in_other_campaigns: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Add contacts active in other campaigns',
|
||||
},
|
||||
sequence_finished_in_other_campaigns: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Add contacts who finished other campaigns',
|
||||
},
|
||||
sequence_same_company_in_same_campaign: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Add contacts even if others from the same company are in the sequence',
|
||||
},
|
||||
contacts_without_ownership_permission: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Add contacts without ownership permission',
|
||||
},
|
||||
add_if_in_queue: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Add contacts even if they are in the queue',
|
||||
},
|
||||
contact_verification_skipped: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Skip contact verification when adding',
|
||||
},
|
||||
user_id: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'ID of the user performing the action',
|
||||
},
|
||||
status: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'Initial status for added contacts: "active" or "paused"',
|
||||
},
|
||||
auto_unpause_at: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-only',
|
||||
description: 'ISO 8601 datetime to automatically unpause contacts',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
/**
|
||||
* Apollo documents every field for this endpoint as a query parameter (no request body),
|
||||
* so `contact_ids[]`/`label_names[]` are appended to the query string alongside the scalar
|
||||
* settings, matching the documented contract.
|
||||
*/
|
||||
url: (params: ApolloSequenceAddContactsParams) => {
|
||||
const hasContactIds = !!params.contact_ids?.length
|
||||
const hasLabelNames = !!params.label_names?.length
|
||||
if (!hasContactIds && !hasLabelNames) {
|
||||
throw new Error(
|
||||
'Apollo sequence add requires either contact_ids or label_names to be provided'
|
||||
)
|
||||
}
|
||||
const qs = new URLSearchParams()
|
||||
qs.set('emailer_campaign_id', params.sequence_id)
|
||||
qs.set('send_email_from_email_account_id', params.send_email_from_email_account_id)
|
||||
for (const id of params.contact_ids ?? []) {
|
||||
if (typeof id === 'string' && id.length > 0) qs.append('contact_ids[]', id)
|
||||
}
|
||||
for (const name of params.label_names ?? []) {
|
||||
if (typeof name === 'string' && name.length > 0) qs.append('label_names[]', name)
|
||||
}
|
||||
if (params.send_email_from_email_address) {
|
||||
qs.set('send_email_from_email_address', params.send_email_from_email_address)
|
||||
}
|
||||
if (params.sequence_no_email !== undefined) {
|
||||
qs.set('sequence_no_email', String(params.sequence_no_email))
|
||||
}
|
||||
if (params.sequence_unverified_email !== undefined) {
|
||||
qs.set('sequence_unverified_email', String(params.sequence_unverified_email))
|
||||
}
|
||||
if (params.sequence_job_change !== undefined) {
|
||||
qs.set('sequence_job_change', String(params.sequence_job_change))
|
||||
}
|
||||
if (params.sequence_active_in_other_campaigns !== undefined) {
|
||||
qs.set(
|
||||
'sequence_active_in_other_campaigns',
|
||||
String(params.sequence_active_in_other_campaigns)
|
||||
)
|
||||
}
|
||||
if (params.sequence_finished_in_other_campaigns !== undefined) {
|
||||
qs.set(
|
||||
'sequence_finished_in_other_campaigns',
|
||||
String(params.sequence_finished_in_other_campaigns)
|
||||
)
|
||||
}
|
||||
if (params.sequence_same_company_in_same_campaign !== undefined) {
|
||||
qs.set(
|
||||
'sequence_same_company_in_same_campaign',
|
||||
String(params.sequence_same_company_in_same_campaign)
|
||||
)
|
||||
}
|
||||
if (params.contacts_without_ownership_permission !== undefined) {
|
||||
qs.set(
|
||||
'contacts_without_ownership_permission',
|
||||
String(params.contacts_without_ownership_permission)
|
||||
)
|
||||
}
|
||||
if (params.add_if_in_queue !== undefined) {
|
||||
qs.set('add_if_in_queue', String(params.add_if_in_queue))
|
||||
}
|
||||
if (params.contact_verification_skipped !== undefined) {
|
||||
qs.set('contact_verification_skipped', String(params.contact_verification_skipped))
|
||||
}
|
||||
if (params.user_id) qs.set('user_id', params.user_id)
|
||||
if (params.status) qs.set('status', params.status)
|
||||
if (params.auto_unpause_at) qs.set('auto_unpause_at', params.auto_unpause_at)
|
||||
return `https://api.apollo.io/api/v1/emailer_campaigns/${params.sequence_id.trim()}/add_contact_ids?${qs.toString()}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: ApolloSequenceAddContactsParams) => ({
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response, params?: ApolloSequenceAddContactsParams) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
// Apollo's response shape for this endpoint varies: some payloads return a flat
|
||||
// `contacts: [...]` array of successfully added contacts, others wrap under
|
||||
// `contacts: { added, skipped }`. Handle both defensively.
|
||||
const contactsField = data?.contacts
|
||||
const added = Array.isArray(contactsField)
|
||||
? contactsField
|
||||
: Array.isArray(contactsField?.added)
|
||||
? contactsField.added
|
||||
: []
|
||||
const skipped = Array.isArray(contactsField?.skipped) ? contactsField.skipped : []
|
||||
const rawSkippedIds = data?.skipped_contact_ids
|
||||
const skippedIds =
|
||||
Array.isArray(rawSkippedIds) || (rawSkippedIds && typeof rawSkippedIds === 'object')
|
||||
? rawSkippedIds
|
||||
: null
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
added,
|
||||
skipped,
|
||||
skipped_contact_ids: skippedIds,
|
||||
emailer_campaign: data?.emailer_campaign ?? null,
|
||||
sequence_id: params?.sequence_id || data?.emailer_campaign?.id || '',
|
||||
total_added: added.length,
|
||||
total_skipped: skipped.length,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
added: {
|
||||
type: 'json',
|
||||
description: 'Array of contact objects successfully added to the sequence',
|
||||
},
|
||||
skipped: {
|
||||
type: 'json',
|
||||
description: 'Array of contact objects that were skipped, with reasons',
|
||||
},
|
||||
skipped_contact_ids: {
|
||||
type: 'json',
|
||||
description:
|
||||
'Skipped contact IDs — either an array of IDs or a hash mapping ID → reason code',
|
||||
optional: true,
|
||||
},
|
||||
emailer_campaign: {
|
||||
type: 'json',
|
||||
description: 'Details of the emailer campaign (id, name)',
|
||||
optional: true,
|
||||
},
|
||||
sequence_id: { type: 'string', description: 'ID of the sequence contacts were added to' },
|
||||
total_added: { type: 'number', description: 'Total number of contacts added' },
|
||||
total_skipped: { type: 'number', description: 'Total number of contacts skipped' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import type { ApolloSequenceSearchParams, ApolloSequenceSearchResponse } from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloSequenceSearchTool: ToolConfig<
|
||||
ApolloSequenceSearchParams,
|
||||
ApolloSequenceSearchResponse
|
||||
> = {
|
||||
id: 'apollo_sequence_search',
|
||||
name: 'Apollo Search Sequences',
|
||||
description: "Search for sequences/campaigns in your team's Apollo account (master key required)",
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key (master key required)',
|
||||
},
|
||||
q_name: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Search sequences by name (e.g., "Outbound Q1", "Follow-up")',
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number for pagination (e.g., 1, 2, 3)',
|
||||
},
|
||||
per_page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page, max 100 (e.g., 25, 50, 100)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: ApolloSequenceSearchParams) => {
|
||||
const qs = new URLSearchParams()
|
||||
qs.set('page', String(params.page || 1))
|
||||
qs.set('per_page', String(Math.min(params.per_page || 25, 100)))
|
||||
if (params.q_name) qs.set('q_name', params.q_name)
|
||||
return `https://api.apollo.io/api/v1/emailer_campaigns/search?${qs.toString()}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: ApolloSequenceSearchParams) => ({
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
sequences: data.emailer_campaigns || [],
|
||||
page: data.pagination?.page || 1,
|
||||
per_page: data.pagination?.per_page || 25,
|
||||
total_entries: data.pagination?.total_entries || 0,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
sequences: {
|
||||
type: 'json',
|
||||
description: 'Array of sequences/campaigns matching the search criteria',
|
||||
},
|
||||
page: { type: 'number', description: 'Current page number' },
|
||||
per_page: { type: 'number', description: 'Results per page' },
|
||||
total_entries: { type: 'number', description: 'Total matching entries' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
import type { ApolloTaskCreateParams, ApolloTaskCreateResponse } from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloTaskCreateTool: ToolConfig<ApolloTaskCreateParams, ApolloTaskCreateResponse> = {
|
||||
id: 'apollo_task_create',
|
||||
name: 'Apollo Create Task',
|
||||
description: 'Create one or more tasks in Apollo (one task per contact_id, master key required)',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key (master key required)',
|
||||
},
|
||||
user_id: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'ID of the Apollo user the task is assigned to',
|
||||
},
|
||||
contact_ids: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Array of contact IDs. One task is created per contact.',
|
||||
},
|
||||
priority: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Task priority: "high", "medium", or "low" (defaults to "medium")',
|
||||
},
|
||||
due_at: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Due date/time in ISO 8601 format (e.g., "2024-12-31T23:59:59Z")',
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Task type: "call", "outreach_manual_email", "linkedin_step_connect", "linkedin_step_message", "linkedin_step_view_profile", "linkedin_step_interact_post", or "action_item"',
|
||||
},
|
||||
status: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Task status: "scheduled", "completed", or "skipped"',
|
||||
},
|
||||
note: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Free-form note providing context for the task',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://api.apollo.io/api/v1/tasks/bulk_create',
|
||||
method: 'POST',
|
||||
headers: (params: ApolloTaskCreateParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
body: (params: ApolloTaskCreateParams) => {
|
||||
const body: Record<string, unknown> = {
|
||||
user_id: params.user_id,
|
||||
contact_ids: params.contact_ids,
|
||||
priority: params.priority || 'medium',
|
||||
due_at: params.due_at,
|
||||
type: params.type,
|
||||
status: params.status,
|
||||
}
|
||||
if (params.note) body.note = params.note
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json().catch(() => null)
|
||||
const tasks = Array.isArray(data?.tasks) ? data.tasks : []
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
tasks,
|
||||
created: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
tasks: { type: 'json', description: 'Array of created tasks (when returned by Apollo)' },
|
||||
created: { type: 'boolean', description: 'Whether the request succeeded' },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import type { ApolloTaskSearchParams, ApolloTaskSearchResponse } from '@/tools/apollo/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const apolloTaskSearchTool: ToolConfig<ApolloTaskSearchParams, ApolloTaskSearchResponse> = {
|
||||
id: 'apollo_task_search',
|
||||
name: 'Apollo Search Tasks',
|
||||
description: 'Search for tasks in Apollo',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
apiKey: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-only',
|
||||
description: 'Apollo API key (master key required)',
|
||||
},
|
||||
sort_by_field: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Sort field: "task_due_at" or "task_priority"',
|
||||
},
|
||||
open_factor_names: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Filter by status. Common values: ["task_types"] for open tasks, ["task_completed_at"] for completed tasks.',
|
||||
},
|
||||
page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Page number for pagination (e.g., 1, 2, 3)',
|
||||
},
|
||||
per_page: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Results per page, max 100 (e.g., 25, 50, 100)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: ApolloTaskSearchParams) => {
|
||||
const qs = new URLSearchParams()
|
||||
qs.set('page', String(params.page || 1))
|
||||
qs.set('per_page', String(Math.min(params.per_page || 25, 100)))
|
||||
if (params.sort_by_field) qs.set('sort_by_field', params.sort_by_field)
|
||||
if (params.open_factor_names?.length) {
|
||||
for (const name of params.open_factor_names) {
|
||||
if (typeof name === 'string' && name) qs.append('open_factor_names[]', name)
|
||||
}
|
||||
}
|
||||
return `https://api.apollo.io/api/v1/tasks/search?${qs.toString()}`
|
||||
},
|
||||
method: 'POST',
|
||||
headers: (params: ApolloTaskSearchParams) => ({
|
||||
'Cache-Control': 'no-cache',
|
||||
'X-Api-Key': params.apiKey,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
throw new Error(`Apollo API error: ${response.status} - ${errorText}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
tasks: data.tasks ?? [],
|
||||
pagination: data.pagination ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
tasks: {
|
||||
type: 'json',
|
||||
description: 'Array of tasks matching the search criteria',
|
||||
},
|
||||
pagination: { type: 'json', description: 'Pagination information', optional: true },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,705 @@
|
||||
import type { ToolResponse } from '@/tools/types'
|
||||
|
||||
// Common types
|
||||
interface ApolloPerson {
|
||||
id: string
|
||||
first_name: string
|
||||
last_name: string
|
||||
name: string
|
||||
title: string
|
||||
email: string
|
||||
organization_name?: string
|
||||
linkedin_url?: string
|
||||
phone_numbers?: Array<{
|
||||
raw_number: string
|
||||
sanitized_number: string
|
||||
type: string
|
||||
}>
|
||||
}
|
||||
|
||||
interface ApolloOrganization {
|
||||
id: string
|
||||
name: string
|
||||
website_url?: string
|
||||
linkedin_url?: string
|
||||
industry?: string
|
||||
phone?: string
|
||||
employees?: number
|
||||
founded_year?: number
|
||||
}
|
||||
|
||||
interface ApolloContact {
|
||||
id: string
|
||||
first_name: string
|
||||
last_name: string
|
||||
email: string
|
||||
title?: string
|
||||
account_id?: string
|
||||
owner_id?: string
|
||||
created_at: string
|
||||
}
|
||||
|
||||
interface ApolloAccount {
|
||||
id: string
|
||||
name: string
|
||||
domain?: string | null
|
||||
website_url?: string | null
|
||||
phone?: string | null
|
||||
sanitized_phone?: string | null
|
||||
raw_address?: string | null
|
||||
owner_id?: string | null
|
||||
account_stage_id?: string | null
|
||||
existence_level?: string
|
||||
show_intent?: boolean
|
||||
has_intent_signal_account?: boolean
|
||||
typed_custom_fields?: Record<string, unknown>
|
||||
created_at: string
|
||||
}
|
||||
|
||||
interface ApolloTask {
|
||||
id: string
|
||||
user_id?: string
|
||||
contact_id?: string
|
||||
account_id?: string
|
||||
type?: string
|
||||
priority?: string
|
||||
status?: string
|
||||
due_at?: string
|
||||
note?: string
|
||||
created_at?: string
|
||||
updated_at?: string
|
||||
}
|
||||
|
||||
interface ApolloOpportunity {
|
||||
id: string
|
||||
team_id?: string
|
||||
name: string
|
||||
account_id?: string | null
|
||||
owner_id?: string | null
|
||||
salesforce_owner_id?: string | null
|
||||
amount?: number | string | null
|
||||
amount_in_team_currency?: number | null
|
||||
forecasted_revenue?: number | null
|
||||
exchange_rate_code?: string
|
||||
exchange_rate_value?: number
|
||||
closed_date?: string | null
|
||||
actual_close_date?: string | null
|
||||
description?: string | null
|
||||
is_closed?: boolean
|
||||
is_won?: boolean
|
||||
stage_name?: string | null
|
||||
opportunity_stage_id?: string | null
|
||||
opportunity_pipeline_id?: string | null
|
||||
source?: string
|
||||
salesforce_id?: string | null
|
||||
forecast_category?: string
|
||||
deal_probability?: number
|
||||
probability?: number | null
|
||||
created_by_id?: string
|
||||
stage_updated_at?: string
|
||||
next_step?: string | null
|
||||
next_step_date?: string | null
|
||||
closed_lost_reason?: string | null
|
||||
closed_won_reason?: string | null
|
||||
last_activity_date?: string
|
||||
existence_level?: string
|
||||
typed_custom_fields?: Record<string, unknown>
|
||||
opportunity_rule_config_statuses?: unknown[]
|
||||
opportunity_contact_roles?: unknown[]
|
||||
currency?: { name?: string; iso_code?: string; symbol?: string }
|
||||
account?: { id?: string; name?: string; website_url?: string | null }
|
||||
created_at: string
|
||||
updated_at?: string
|
||||
}
|
||||
|
||||
interface ApolloBaseParams {
|
||||
apiKey: string
|
||||
}
|
||||
|
||||
// People Search Types
|
||||
export interface ApolloPeopleSearchParams extends ApolloBaseParams {
|
||||
person_titles?: string[]
|
||||
include_similar_titles?: boolean
|
||||
person_locations?: string[]
|
||||
person_seniorities?: string[]
|
||||
organization_ids?: string[]
|
||||
organization_names?: string[]
|
||||
organization_locations?: string[]
|
||||
q_organization_domains_list?: string[]
|
||||
organization_num_employees_ranges?: string[]
|
||||
contact_email_status?: string[]
|
||||
q_keywords?: string
|
||||
page?: number
|
||||
per_page?: number
|
||||
}
|
||||
|
||||
export interface ApolloPeopleSearchResponse extends ToolResponse {
|
||||
output: {
|
||||
people: ApolloPerson[]
|
||||
page: number
|
||||
per_page: number
|
||||
total_entries: number
|
||||
}
|
||||
}
|
||||
|
||||
// People Enrichment Types
|
||||
export interface ApolloPeopleEnrichParams extends ApolloBaseParams {
|
||||
first_name?: string
|
||||
last_name?: string
|
||||
name?: string
|
||||
id?: string
|
||||
hashed_email?: string
|
||||
organization_name?: string
|
||||
email?: string
|
||||
domain?: string
|
||||
linkedin_url?: string
|
||||
reveal_personal_emails?: boolean
|
||||
reveal_phone_number?: boolean
|
||||
webhook_url?: string
|
||||
}
|
||||
|
||||
export interface ApolloPeopleEnrichResponse extends ToolResponse {
|
||||
output: {
|
||||
person: ApolloPerson | null
|
||||
enriched: boolean
|
||||
}
|
||||
}
|
||||
|
||||
// Bulk People Enrichment Types
|
||||
export interface ApolloPeopleBulkEnrichParams extends ApolloBaseParams {
|
||||
people: Array<{
|
||||
first_name?: string
|
||||
last_name?: string
|
||||
name?: string
|
||||
email?: string
|
||||
hashed_email?: string
|
||||
organization_name?: string
|
||||
domain?: string
|
||||
id?: string
|
||||
linkedin_url?: string
|
||||
}>
|
||||
reveal_personal_emails?: boolean
|
||||
reveal_phone_number?: boolean
|
||||
webhook_url?: string
|
||||
}
|
||||
|
||||
export interface ApolloPeopleBulkEnrichResponse extends ToolResponse {
|
||||
output: {
|
||||
matches: Array<ApolloPerson | null>
|
||||
total_requested_enrichments: number
|
||||
unique_enriched_records: number
|
||||
missing_records: number | null
|
||||
credits_consumed: number | null
|
||||
}
|
||||
}
|
||||
|
||||
// Organization Search Types
|
||||
export interface ApolloOrganizationSearchParams extends ApolloBaseParams {
|
||||
organization_locations?: string[]
|
||||
organization_not_locations?: string[]
|
||||
organization_num_employees_ranges?: string[]
|
||||
q_organization_keyword_tags?: string[]
|
||||
q_organization_name?: string
|
||||
organization_ids?: string[]
|
||||
q_organization_domains_list?: string[]
|
||||
page?: number
|
||||
per_page?: number
|
||||
}
|
||||
|
||||
export interface ApolloOrganizationSearchResponse extends ToolResponse {
|
||||
output: {
|
||||
organizations: ApolloOrganization[]
|
||||
page: number
|
||||
per_page: number
|
||||
total_entries: number
|
||||
}
|
||||
}
|
||||
|
||||
// Organization Enrichment Types
|
||||
export interface ApolloOrganizationEnrichParams extends ApolloBaseParams {
|
||||
domain: string
|
||||
}
|
||||
|
||||
export interface ApolloOrganizationEnrichResponse extends ToolResponse {
|
||||
output: {
|
||||
organization: ApolloOrganization | null
|
||||
enriched: boolean
|
||||
}
|
||||
}
|
||||
|
||||
// Bulk Organization Enrichment Types
|
||||
export interface ApolloOrganizationBulkEnrichParams extends ApolloBaseParams {
|
||||
domains: string[]
|
||||
}
|
||||
|
||||
export interface ApolloOrganizationBulkEnrichResponse extends ToolResponse {
|
||||
output: {
|
||||
organizations: ApolloOrganization[]
|
||||
total: number
|
||||
enriched: number
|
||||
missing_records: number
|
||||
unique_domains: number
|
||||
}
|
||||
}
|
||||
|
||||
// Contact Create Types
|
||||
export interface ApolloContactCreateParams extends ApolloBaseParams {
|
||||
first_name: string
|
||||
last_name: string
|
||||
email?: string
|
||||
title?: string
|
||||
account_id?: string
|
||||
owner_id?: string
|
||||
organization_name?: string
|
||||
website_url?: string
|
||||
label_names?: string[]
|
||||
contact_stage_id?: string
|
||||
present_raw_address?: string
|
||||
direct_phone?: string
|
||||
corporate_phone?: string
|
||||
mobile_phone?: string
|
||||
home_phone?: string
|
||||
other_phone?: string
|
||||
typed_custom_fields?: Record<string, unknown>
|
||||
run_dedupe?: boolean
|
||||
}
|
||||
|
||||
export interface ApolloContactCreateResponse extends ToolResponse {
|
||||
output: {
|
||||
contact: ApolloContact | null
|
||||
created: boolean
|
||||
}
|
||||
}
|
||||
|
||||
// Contact Update Types
|
||||
export interface ApolloContactUpdateParams extends ApolloBaseParams {
|
||||
contact_id: string
|
||||
first_name?: string
|
||||
last_name?: string
|
||||
email?: string
|
||||
title?: string
|
||||
account_id?: string
|
||||
owner_id?: string
|
||||
organization_name?: string
|
||||
website_url?: string
|
||||
label_names?: string[]
|
||||
contact_stage_id?: string
|
||||
present_raw_address?: string
|
||||
direct_phone?: string
|
||||
corporate_phone?: string
|
||||
mobile_phone?: string
|
||||
home_phone?: string
|
||||
other_phone?: string
|
||||
typed_custom_fields?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface ApolloContactUpdateResponse extends ToolResponse {
|
||||
output: {
|
||||
contact: ApolloContact | null
|
||||
updated: boolean
|
||||
}
|
||||
}
|
||||
|
||||
// Contact Bulk Create Types
|
||||
export interface ApolloContactBulkCreateParams extends ApolloBaseParams {
|
||||
contacts: Array<{
|
||||
first_name?: string
|
||||
last_name?: string
|
||||
email?: string
|
||||
title?: string
|
||||
organization_name?: string
|
||||
account_id?: string
|
||||
owner_id?: string
|
||||
contact_stage_id?: string
|
||||
linkedin_url?: string
|
||||
phone?: string
|
||||
phone_numbers?: Array<{ raw_number: string; position?: number }>
|
||||
contact_emails?: Array<{ email: string; position?: number }>
|
||||
salesforce_contact_id?: string
|
||||
hubspot_id?: string
|
||||
team_id?: string
|
||||
typed_custom_fields?: Record<string, unknown>
|
||||
[key: string]: unknown
|
||||
}>
|
||||
run_dedupe?: boolean
|
||||
append_label_names?: string[]
|
||||
}
|
||||
|
||||
export interface ApolloContactBulkCreateResponse extends ToolResponse {
|
||||
output: {
|
||||
created_contacts: ApolloContact[]
|
||||
existing_contacts: ApolloContact[]
|
||||
total_submitted: number
|
||||
created: number
|
||||
existing: number
|
||||
}
|
||||
}
|
||||
|
||||
// Contact Bulk Update Types
|
||||
export interface ApolloContactBulkUpdateParams extends ApolloBaseParams {
|
||||
contact_ids?: string[]
|
||||
contact_attributes?: Array<{ id: string; [key: string]: unknown }> | Record<string, unknown>
|
||||
async?: boolean
|
||||
}
|
||||
|
||||
export interface ApolloContactBulkUpdateResponse extends ToolResponse {
|
||||
output: {
|
||||
contacts: ApolloContact[]
|
||||
entity_progress_job: Record<string, unknown> | null
|
||||
job_id: string | null
|
||||
message: string | null
|
||||
}
|
||||
}
|
||||
|
||||
// Contact Search Types
|
||||
export interface ApolloContactSearchParams extends ApolloBaseParams {
|
||||
q_keywords?: string
|
||||
contact_stage_ids?: string[]
|
||||
contact_label_ids?: string[]
|
||||
sort_by_field?: string
|
||||
sort_ascending?: boolean
|
||||
page?: number
|
||||
per_page?: number
|
||||
}
|
||||
|
||||
interface ApolloPagination {
|
||||
page?: number
|
||||
per_page?: number
|
||||
total_entries?: number
|
||||
total_pages?: number
|
||||
}
|
||||
|
||||
export interface ApolloContactSearchResponse extends ToolResponse {
|
||||
output: {
|
||||
contacts: ApolloContact[]
|
||||
pagination: ApolloPagination | null
|
||||
}
|
||||
}
|
||||
|
||||
// Account Create Types
|
||||
export interface ApolloAccountCreateParams extends ApolloBaseParams {
|
||||
name: string
|
||||
domain?: string
|
||||
phone?: string
|
||||
owner_id?: string
|
||||
account_stage_id?: string
|
||||
raw_address?: string
|
||||
typed_custom_fields?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface ApolloAccountCreateResponse extends ToolResponse {
|
||||
output: {
|
||||
account: ApolloAccount | null
|
||||
created: boolean
|
||||
}
|
||||
}
|
||||
|
||||
// Account Update Types
|
||||
export interface ApolloAccountUpdateParams extends ApolloBaseParams {
|
||||
account_id: string
|
||||
name?: string
|
||||
domain?: string
|
||||
phone?: string
|
||||
owner_id?: string
|
||||
account_stage_id?: string
|
||||
raw_address?: string
|
||||
typed_custom_fields?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface ApolloAccountUpdateResponse extends ToolResponse {
|
||||
output: {
|
||||
account: ApolloAccount | null
|
||||
updated: boolean
|
||||
}
|
||||
}
|
||||
|
||||
// Account Search Types
|
||||
export interface ApolloAccountSearchParams extends ApolloBaseParams {
|
||||
q_organization_name?: string
|
||||
account_stage_ids?: string[]
|
||||
account_label_ids?: string[]
|
||||
sort_by_field?: string
|
||||
sort_ascending?: boolean
|
||||
page?: number
|
||||
per_page?: number
|
||||
}
|
||||
|
||||
export interface ApolloAccountSearchResponse extends ToolResponse {
|
||||
output: {
|
||||
accounts: ApolloAccount[]
|
||||
pagination: ApolloPagination | null
|
||||
}
|
||||
}
|
||||
|
||||
// Account Bulk Create Types
|
||||
export interface ApolloAccountBulkCreateParams extends ApolloBaseParams {
|
||||
accounts: Array<{
|
||||
name?: string
|
||||
domain?: string
|
||||
phone?: string
|
||||
phone_status_cd?: string
|
||||
raw_address?: string
|
||||
owner_id?: string
|
||||
linkedin_url?: string
|
||||
facebook_url?: string
|
||||
twitter_url?: string
|
||||
salesforce_id?: string
|
||||
hubspot_id?: string
|
||||
[key: string]: unknown
|
||||
}>
|
||||
append_label_names?: string[]
|
||||
run_dedupe?: boolean
|
||||
}
|
||||
|
||||
export interface ApolloAccountBulkCreateResponse extends ToolResponse {
|
||||
output: {
|
||||
created_accounts: ApolloAccount[]
|
||||
existing_accounts: ApolloAccount[]
|
||||
failed_accounts: Array<Record<string, unknown>>
|
||||
total_submitted: number
|
||||
created: number
|
||||
existing: number
|
||||
failed: number
|
||||
}
|
||||
}
|
||||
|
||||
// Account Bulk Update Types
|
||||
export interface ApolloAccountBulkUpdateParams extends ApolloBaseParams {
|
||||
account_ids?: string[]
|
||||
name?: string
|
||||
owner_id?: string
|
||||
account_stage_id?: string
|
||||
account_attributes?: Array<{ id: string; [key: string]: unknown }> | Record<string, unknown>
|
||||
async?: boolean
|
||||
}
|
||||
|
||||
export interface ApolloAccountBulkUpdateResponse extends ToolResponse {
|
||||
output: {
|
||||
accounts: ApolloAccount[]
|
||||
account_ids: string[]
|
||||
entity_progress_job: Record<string, unknown> | null
|
||||
job_id: string | null
|
||||
message: string | null
|
||||
}
|
||||
}
|
||||
|
||||
// Sequence Add Contacts Types
|
||||
export interface ApolloSequenceAddContactsParams extends ApolloBaseParams {
|
||||
sequence_id: string
|
||||
contact_ids?: string[]
|
||||
label_names?: string[]
|
||||
send_email_from_email_account_id: string
|
||||
send_email_from_email_address?: string
|
||||
sequence_no_email?: boolean
|
||||
sequence_unverified_email?: boolean
|
||||
sequence_job_change?: boolean
|
||||
sequence_active_in_other_campaigns?: boolean
|
||||
sequence_finished_in_other_campaigns?: boolean
|
||||
sequence_same_company_in_same_campaign?: boolean
|
||||
contacts_without_ownership_permission?: boolean
|
||||
add_if_in_queue?: boolean
|
||||
contact_verification_skipped?: boolean
|
||||
user_id?: string
|
||||
status?: string
|
||||
auto_unpause_at?: string
|
||||
}
|
||||
|
||||
interface ApolloSequenceAddedContact {
|
||||
id: string
|
||||
first_name?: string
|
||||
last_name?: string
|
||||
email?: string
|
||||
status?: string
|
||||
opened_rate?: number | null
|
||||
replied_rate?: number | null
|
||||
}
|
||||
|
||||
interface ApolloSequenceSkippedContact {
|
||||
id: string
|
||||
reason: string
|
||||
}
|
||||
|
||||
export interface ApolloSequenceAddContactsResponse extends ToolResponse {
|
||||
output: {
|
||||
added: ApolloSequenceAddedContact[]
|
||||
skipped: ApolloSequenceSkippedContact[]
|
||||
skipped_contact_ids: string[] | Record<string, string> | null
|
||||
emailer_campaign: { id: string; name: string } | null
|
||||
sequence_id: string
|
||||
total_added: number
|
||||
total_skipped: number
|
||||
}
|
||||
}
|
||||
|
||||
// Task Create Types
|
||||
export interface ApolloTaskCreateParams extends ApolloBaseParams {
|
||||
user_id: string
|
||||
contact_ids: string[]
|
||||
priority?: string
|
||||
due_at: string
|
||||
type: string
|
||||
status: string
|
||||
note?: string
|
||||
}
|
||||
|
||||
export interface ApolloTaskCreateResponse extends ToolResponse {
|
||||
output: {
|
||||
tasks: ApolloTask[]
|
||||
created: boolean
|
||||
}
|
||||
}
|
||||
|
||||
// Task Search Types
|
||||
export interface ApolloTaskSearchParams extends ApolloBaseParams {
|
||||
sort_by_field?: string
|
||||
open_factor_names?: string[]
|
||||
page?: number
|
||||
per_page?: number
|
||||
}
|
||||
|
||||
export interface ApolloTaskSearchResponse extends ToolResponse {
|
||||
output: {
|
||||
tasks: ApolloTask[]
|
||||
pagination: ApolloPagination | null
|
||||
}
|
||||
}
|
||||
|
||||
// Email Accounts List Types
|
||||
export interface ApolloEmailAccountsParams extends ApolloBaseParams {}
|
||||
|
||||
interface ApolloEmailAccount {
|
||||
id: string | number
|
||||
email: string
|
||||
type?: string
|
||||
active?: boolean
|
||||
default?: boolean
|
||||
linked_at?: string | null
|
||||
}
|
||||
|
||||
export interface ApolloEmailAccountsResponse extends ToolResponse {
|
||||
output: {
|
||||
email_accounts: ApolloEmailAccount[]
|
||||
total: number
|
||||
}
|
||||
}
|
||||
|
||||
// Opportunity Create Types
|
||||
export interface ApolloOpportunityCreateParams extends ApolloBaseParams {
|
||||
name: string
|
||||
account_id?: string
|
||||
amount?: string
|
||||
opportunity_stage_id?: string
|
||||
owner_id?: string
|
||||
closed_date?: string
|
||||
typed_custom_fields?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface ApolloOpportunityCreateResponse extends ToolResponse {
|
||||
output: {
|
||||
opportunity: ApolloOpportunity | null
|
||||
created: boolean
|
||||
}
|
||||
}
|
||||
|
||||
// Opportunity Search Types
|
||||
export interface ApolloOpportunitySearchParams extends ApolloBaseParams {
|
||||
sort_by_field?: string
|
||||
page?: number
|
||||
per_page?: number
|
||||
}
|
||||
|
||||
export interface ApolloOpportunitySearchResponse extends ToolResponse {
|
||||
output: {
|
||||
opportunities: ApolloOpportunity[]
|
||||
page: number
|
||||
per_page: number
|
||||
total_entries: number
|
||||
}
|
||||
}
|
||||
|
||||
// Opportunity Get Types
|
||||
export interface ApolloOpportunityGetParams extends ApolloBaseParams {
|
||||
opportunity_id: string
|
||||
}
|
||||
|
||||
export interface ApolloOpportunityGetResponse extends ToolResponse {
|
||||
output: {
|
||||
opportunity: ApolloOpportunity | null
|
||||
found: boolean
|
||||
}
|
||||
}
|
||||
|
||||
// Opportunity Update Types
|
||||
export interface ApolloOpportunityUpdateParams extends ApolloBaseParams {
|
||||
opportunity_id: string
|
||||
name?: string
|
||||
amount?: string
|
||||
opportunity_stage_id?: string
|
||||
owner_id?: string
|
||||
closed_date?: string
|
||||
typed_custom_fields?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export interface ApolloOpportunityUpdateResponse extends ToolResponse {
|
||||
output: {
|
||||
opportunity: ApolloOpportunity | null
|
||||
updated: boolean
|
||||
}
|
||||
}
|
||||
|
||||
// Sequence/Campaign Types
|
||||
interface ApolloSequence {
|
||||
id: string
|
||||
name: string
|
||||
active: boolean
|
||||
num_steps?: number
|
||||
num_contacts?: number
|
||||
created_at: string
|
||||
updated_at?: string
|
||||
user_id?: string
|
||||
permissions?: string
|
||||
}
|
||||
|
||||
// Sequence Search Types
|
||||
export interface ApolloSequenceSearchParams extends ApolloBaseParams {
|
||||
q_name?: string
|
||||
page?: number
|
||||
per_page?: number
|
||||
}
|
||||
|
||||
export interface ApolloSequenceSearchResponse extends ToolResponse {
|
||||
output: {
|
||||
sequences: ApolloSequence[]
|
||||
page: number
|
||||
per_page: number
|
||||
total_entries: number
|
||||
}
|
||||
}
|
||||
|
||||
// Union type for all Apollo responses
|
||||
export type ApolloResponse =
|
||||
| ApolloPeopleSearchResponse
|
||||
| ApolloPeopleEnrichResponse
|
||||
| ApolloPeopleBulkEnrichResponse
|
||||
| ApolloOrganizationSearchResponse
|
||||
| ApolloOrganizationEnrichResponse
|
||||
| ApolloOrganizationBulkEnrichResponse
|
||||
| ApolloContactCreateResponse
|
||||
| ApolloContactUpdateResponse
|
||||
| ApolloContactBulkCreateResponse
|
||||
| ApolloContactBulkUpdateResponse
|
||||
| ApolloContactSearchResponse
|
||||
| ApolloAccountCreateResponse
|
||||
| ApolloAccountUpdateResponse
|
||||
| ApolloAccountSearchResponse
|
||||
| ApolloAccountBulkCreateResponse
|
||||
| ApolloAccountBulkUpdateResponse
|
||||
| ApolloSequenceAddContactsResponse
|
||||
| ApolloTaskCreateResponse
|
||||
| ApolloTaskSearchResponse
|
||||
| ApolloEmailAccountsResponse
|
||||
| ApolloSequenceSearchResponse
|
||||
| ApolloOpportunityCreateResponse
|
||||
| ApolloOpportunitySearchResponse
|
||||
| ApolloOpportunityGetResponse
|
||||
| ApolloOpportunityUpdateResponse
|
||||
Reference in New Issue
Block a user