/** * Apollo.io Opportunity/Deal Tools */ import { z } from 'zod'; import type { ApolloClient } from '../client/apollo-client.js'; const ListOpportunitiesInput = z.object({ page: z.number().min(1).default(1).describe('Page number to retrieve (starts at 1)'), per_page: z.number().min(1).max(100).default(25).describe('Number of opportunities per page (max 100)'), status: z.enum(['open', 'won', 'lost']).optional().describe('Filter by opportunity status'), owner_id: z.string().optional().describe('Filter by opportunity owner user ID'), }); const CreateOpportunityInput = z.object({ name: z.string().describe('Name of the opportunity (e.g., "Acme Corp - Enterprise Plan")'), amount: z.number().optional().describe('Deal value/amount in dollars'), account_id: z.string().optional().describe('ID of the associated account/company'), contact_id: z.string().optional().describe('ID of the primary contact'), stage_id: z.string().optional().describe('ID of the opportunity stage (defaults to first stage)'), closed_date: z.string().optional().describe('Expected or actual close date in ISO 8601 format'), probability: z.number().min(0).max(100).optional().describe('Win probability percentage (0-100)'), }); const UpdateOpportunityInput = z.object({ id: z.string().describe('The unique ID of the opportunity to update'), name: z.string().optional().describe('Updated opportunity name'), amount: z.number().optional().describe('Updated deal value/amount'), stage_id: z.string().optional().describe('Updated stage ID (to advance or change stage)'), status: z.enum(['open', 'won', 'lost']).optional().describe('Updated opportunity status'), closed_date: z.string().optional().describe('Updated close date in ISO 8601 format'), probability: z.number().min(0).max(100).optional().describe('Updated win probability percentage (0-100)'), }); export default [ { name: 'apollo_list_opportunities', description: 'Lists opportunities (deals) from Apollo.io with pagination support. Use when the user wants to review their sales pipeline, check deal values, or analyze opportunities by stage. Returns paginated results showing opportunity names, amounts, stages, close dates, and associated accounts/contacts. Supports filtering by status (open/won/lost) and owner. Up to 100 opportunities per page.', inputSchema: { type: 'object' as const, properties: { page: { type: 'number', description: 'Page number to retrieve (starts at 1)', default: 1, }, per_page: { type: 'number', description: 'Number of opportunities per page (max 100)', default: 25, }, status: { type: 'string', enum: ['open', 'won', 'lost'], description: 'Filter by opportunity status', }, owner_id: { type: 'string', description: 'Filter by opportunity owner user ID (optional)', }, }, }, handler: async (input: unknown, client: ApolloClient) => { const validated = ListOpportunitiesInput.parse(input); const result = await client.get('/opportunities', validated); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; }, }, { name: 'apollo_create_opportunity', description: 'Creates a new opportunity (deal) in Apollo.io. Use when the user identifies a qualified prospect, receives a request for proposal, or wants to track a potential sale. Opportunities can be associated with contacts and accounts, have monetary values, and move through pipeline stages. Returns the newly created opportunity with assigned ID.', inputSchema: { type: 'object' as const, properties: { name: { type: 'string', description: 'Name of the opportunity (e.g., "Acme Corp - Enterprise Plan")', }, amount: { type: 'number', description: 'Deal value/amount in dollars (optional)', }, account_id: { type: 'string', description: 'ID of the associated account/company (optional)', }, contact_id: { type: 'string', description: 'ID of the primary contact (optional)', }, stage_id: { type: 'string', description: 'ID of the opportunity stage (optional, defaults to first stage)', }, closed_date: { type: 'string', description: 'Expected or actual close date in ISO 8601 format (optional)', }, probability: { type: 'number', description: 'Win probability percentage (0-100, optional)', }, }, required: ['name'], }, handler: async (input: unknown, client: ApolloClient) => { const validated = CreateOpportunityInput.parse(input); const result = await client.post('/opportunities', validated); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; }, }, { name: 'apollo_update_opportunity', description: 'Updates an existing opportunity in Apollo.io. Use when the user needs to modify deal details, change stage, update amount, adjust close date, or mark an opportunity as won or lost. Essential for maintaining accurate pipeline data. Returns the updated opportunity record.', inputSchema: { type: 'object' as const, properties: { id: { type: 'string', description: 'The unique ID of the opportunity to update', }, name: { type: 'string', description: 'Updated opportunity name', }, amount: { type: 'number', description: 'Updated deal value/amount', }, stage_id: { type: 'string', description: 'Updated stage ID (to advance or change stage)', }, status: { type: 'string', enum: ['open', 'won', 'lost'], description: 'Updated opportunity status', }, closed_date: { type: 'string', description: 'Updated close date in ISO 8601 format', }, probability: { type: 'number', description: 'Updated win probability percentage (0-100)', }, }, required: ['id'], }, handler: async (input: unknown, client: ApolloClient) => { const validated = UpdateOpportunityInput.parse(input); const { id, ...updateData } = validated; const result = await client.patch(`/opportunities/${id}`, updateData); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; }, }, ];