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

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -0,0 +1,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,
},
},
}
+106
View File
@@ -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' },
},
}
+116
View File
@@ -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 },
},
}
+114
View File
@@ -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,
},
},
}
+188
View File
@@ -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' },
},
}
+115
View File
@@ -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 },
},
}
+187
View File
@@ -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' },
},
}
+54
View File
@@ -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' },
},
}
+26
View File
@@ -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'
+115
View File
@@ -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' },
},
}
+64
View File
@@ -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' },
},
}
+116
View File
@@ -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' },
},
}
+125
View File
@@ -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,
},
},
}
+151
View File
@@ -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' },
},
}
+189
View File
@@ -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' },
},
}
+83
View File
@@ -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' },
},
}
+106
View File
@@ -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' },
},
}
+88
View File
@@ -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 },
},
}
+705
View File
@@ -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