Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Implement Apollo.io reference architecture. Use when designing Apollo integrations, establishing patterns, or building production-grade sales intelligence systems. Trigger with phrases like "apollo architecture", "apollo system design", "apollo integration patterns", "apollo best practices architecture".
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | 39% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 102% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 146% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 165% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 41% | 0% |
Production-ready reference architecture for Apollo.io integrations. Layered design with API client, service layer, background jobs, database models, CRM sync, and deals pipeline — all built around Apollo's REST API with correct endpoints and x-api-key authentication.
┌───────────────────────────────────────────────┐
│ API Layer │ Express routes
│ POST /api/leads/search GET /api/org/:d │ POST /api/deals
├───────────────────────────────────────────────┤
│ Service Layer │ Business logic
│ LeadService EnrichService DealService │ SequenceService
├───────────────────────────────────────────────┤
│ Client Layer │ Apollo API wrapper
│ ApolloClient RateLimiter Cache │ CreditTracker
├───────────────────────────────────────────────┤
│ Background Jobs │ BullMQ queues
│ EnrichJob SyncJob StageChangeJob │ TaskCreatorJob
├───────────────────────────────────────────────┤
│ Data Layer │ Prisma/TypeORM
│ Contact Organization Deal AuditLog │
└───────────────────────────────────────────────┘typescript// src/services/lead-service.ts import { getApolloClient } from '../apollo/client'; import { withRetry } from '../apollo/retry'; import { cachedRequest } from '../apollo/cache'; export class LeadService { private client = getApolloClient(); async searchPeople(params: { domains: string[]; titles?: string[]; seniorities?: string[]; page?: number }) { return cachedRequest('/mixed_people/api_search', () => withRetry(() => this.client.post('/mixed_people/api_search', { q_organization_domains_list: params.domains, person_titles: params.titles, person_seniorities: params.seniorities, page: params.page ?? 1, per_page: 100, })), params, ); } async enrichPerson(email: string) { return withRetry(() => this.client.post('/people/match', { email })); } async enrichOrg(domain: string) { return cachedRequest('/organizations/enrich', () => withRetry(() => this.client.get('/organizations/enrich', { params: { domain } })), { domain }, ); } }
Apollo has a full Deals API for tracking revenue pipeline.
typescript// src/services/deal-service.ts export class DealService { private client = getApolloClient(); async createDeal(params: { name: string; amount: number; ownerId: string; // Apollo user ID accountId?: string; // Apollo account ID contactIds?: string[]; // Apollo contact IDs stageId?: string; // Deal stage ID }) { const { data } = await this.client.post('/opportunities', { name: params.name, amount: params.amount, owner_id: params.ownerId, account_id: params.accountId, contact_ids: params.contactIds, opportunity_stage_id: params.stageId, }); return { dealId: data.opportunity.id, name: data.opportunity.name }; } async listDeals(page: number = 1) { const { data } = await this.client.post('/opportunities/search', { page, per_page: 50 }); return data.opportunities.map((d: any) => ({ id: d.id, name: d.name, amount: d.amount, stage: d.opportunity_stage?.name, owner: d.owner?.name, })); } async getDealStages() { const { data } = await this.client.get('/opportunity_stages'); return data.opportunity_stages.map((s: any) => ({ id: s.id, name: s.name, order: s.display_order })); } async updateDeal(dealId: string, updates: { amount?: number; stageId?: string }) { await this.client.patch(`/opportunities/${dealId}`, { amount: updates.amount, opportunity_stage_id: updates.stageId, }); } }
typescript// src/jobs/enrichment-job.ts import { Queue, Worker, Job } from 'bullmq'; import { LeadService } from '../services/lead-service'; const connection = { host: process.env.REDIS_HOST ?? 'localhost', port: 6379 }; export const enrichmentQueue = new Queue('apollo-enrichment', { connection, defaultJobOptions: { attempts: 3, backoff: { type: 'exponential', delay: 5000 }, removeOnComplete: 1000, }, }); const leadService = new LeadService(); new Worker('apollo-enrichment', async (job: Job) => { switch (job.name) { case 'enrich-person': return leadService.enrichPerson(job.data.email); case 'enrich-org': return leadService.enrichOrg(job.data.domain); case 'bulk-search': { const results: any[] = []; for (const domain of job.data.domains) { const { data } = await leadService.searchPeople({ domains: [domain] }); results.push(...data.people); await job.updateProgress(results.length); } return { total: results.length }; } } }, { connection, concurrency: 3, limiter: { max: 50, duration: 60_000 } });
typescript// src/models/contact.ts (Prisma schema excerpt) // model Contact { // id String @id @default(cuid()) // apolloId String @unique // email String @unique // name String // title String? // seniority String? // phone String? // linkedinUrl String? // organizationId String? // rawApolloData Json? // enrichedAt DateTime? // createdAt DateTime @default(now()) // updatedAt DateTime @updatedAt // } // TypeORM version import { Entity, Column, PrimaryColumn, CreateDateColumn, UpdateDateColumn } from 'typeorm'; @Entity('contacts') export class Contact { @PrimaryColumn() apolloId: string; @Column({ unique: true }) email: string; @Column() name: string; @Column({ nullable: true }) title: string; @Column({ nullable: true }) seniority: string; @Column({ nullable: true }) phone: string; @Column({ nullable: true }) linkedinUrl: string; @Column({ type: 'jsonb', nullable: true }) rawApolloData: Record<string, any>; @Column({ nullable: true }) enrichedAt: Date; @CreateDateColumn() createdAt: Date; @UpdateDateColumn() updatedAt: Date; }
typescript// src/api/routes.ts import { Router } from 'express'; import { LeadService } from '../services/lead-service'; import { DealService } from '../services/deal-service'; const router = Router(); const leads = new LeadService(); const deals = new DealService(); router.post('/api/leads/search', async (req, res) => { const { data } = await leads.searchPeople(req.body); res.json({ leads: data.people, pagination: data.pagination }); }); router.post('/api/leads/enrich', async (req, res) => { const { data } = await leads.enrichPerson(req.body.email); res.json({ contact: data.person }); }); router.get('/api/organizations/:domain', async (req, res) => { const { data } = await leads.enrichOrg(req.params.domain); res.json({ organization: data.organization }); }); router.post('/api/deals', async (req, res) => { const result = await deals.createDeal(req.body); res.json(result); }); router.get('/api/deals', async (req, res) => { const list = await deals.listDeals(parseInt(req.query.page as string) || 1); res.json({ deals: list }); }); export { router };
LeadService with cached search and retried enrichmentDealService with create, list, update, and stage management| Layer | Strategy | |-------|----------| | Client | Retry with backoff, circuit breaker for prolonged outages | | Service | Cache fallback on failure, credit budget enforcement | | Jobs | 3 retries with exponential backoff, dead letter after max | | API | Structured JSON error responses with error codes |
Proceed to apollo-multi-env-setup for environment configuration.
Other measured skills in the registry, with their headline benchmark lift.