Skip to content

feat(backend): Apollo prospect search + add to sequence endpoints#154

Merged
anujeet98 merged 3 commits into
mainfrom
feat/prospect-search-backend
Jun 23, 2026
Merged

feat(backend): Apollo prospect search + add to sequence endpoints#154
anujeet98 merged 3 commits into
mainfrom
feat/prospect-search-backend

Conversation

@Rishavraaj

Copy link
Copy Markdown
Contributor

Summary

Implements the backend for prospect search and the "Add Contacts to Sequence" feature. People search uses Apollo's mixed_people/api_search endpoint via API key — confirmed free (not on Apollo's credit-consuming endpoint list). Organization autocomplete uses accounts/search (also free). Sequence enrollment uses the existing MCP infrastructure.


What changed

Backend — apps/backend

New: apollo-prospects.service.ts

  • searchPeople()POST /mixed_people/api_search with API key auth
    • Filters: name (q_keywords), job titles (person_titles[]), locations (person_locations[]), company domain (q_organization_domains_list[])
    • Sends either domain filter or org ID filter, never both simultaneously (they conflict in Apollo's API)
    • Returns obfuscated profile data — no enrichment credits consumed
  • searchOrganizations()GET /accounts/search with API key auth
    • Searches your Apollo CRM accounts by name, returns { id, name, domain }
    • Free endpoint, not on Apollo's credit-consuming list
    • Returns primary_domain for use with the domain-based people filter
  • addPeopleToSequence() — MCP apollo_emailer_campaigns_add_contact_ids
    • Converts raw Apollo person IDs to contacts via MCP apollo_contacts_create
    • Enrolls all contact IDs into the sequence
    • Returns failedPersonIds[] for partial failure handling
    • Creates best-effort Zuko CRM contact records for new prospects

New: dto/prospects.dto.ts

  • SearchProspectsDto — validated with class-validator, supports personName, personTitles[], personLocations[], organizationIds[], organizationDomains[], page, perPage
  • AddPeopleToSequenceDtosequenceId, contactIds[], personIds[], personData[]

New: apollo-prospects.controller.ts

  • POST /integrations/apollo/prospects/search
  • GET /integrations/apollo/organizations/search?name=
  • POST /integrations/apollo/prospects/add-to-sequence

Modified: integrations.module.ts

  • Registers ApolloProspectsController, ApolloProspectsService, ContactsRepository, ConfigModule

Modified: apollo-integration.service.ts

  • Added person_read and mixed_people_api_search to OAuth scopes list

Modified: apollo-mcp.service.ts

  • Added listTools() debug helper for MCP tool discovery

Frontend — apps/web

Modified: lib/api/apollo.ts

  • OrgSearchResult — added domain?: string field
  • SearchProspectsParams — added organizationDomains?: string[]
  • apolloProspectsApi.searchOrgs() return type updated

Modified: server/query-options.ts

  • getProspectSearch — added organizationDomains param and enabled guard

Modified: AddContactsDialog.tsx

  • Debounce increased from 500ms → 800ms to reduce API calls
  • Name filter requires 3+ characters before triggering search
  • searchParams passes both organizationIds and organizationDomains (backend uses domain preferentially)
  • OrgOption type updated with domain field
  • Empty state text updated

Credit usage

Confirmed via Apollo's official API pricing docs (docs.apollo.io/docs/api-pricing):

Endpoint Credit cost
mixed_people/api_search ✅ Free — not on the list
accounts/search ✅ Free — not on the list
mixed_companies/search ❌ Costs credits — not used
people/match, organizations/enrich ❌ Costs credits — not used

Architecture note

People search and org autocomplete use API key auth (x-api-key header) — this is required because mixed_people/api_search is not accessible via OAuth Bearer token even when the mixed_people_api_search scope is registered on the OAuth app. The MCP-based sequence operations continue to use OAuth as before.


Testing

  • Search by name → results from Apollo's 230M+ database
  • Search by job title (tag input, press Enter) → filters by title
  • Search by location (tag input) → filters by location
  • Search company name → autocomplete shows matching accounts → selecting filters people by domain
  • Name + company combined → returns people at that company matching the name
  • Select people → "Add to sequence" button activates
  • Add to sequence → toast success, dialog closes
  • Partial failure → toast warning with count of failed conversions
  • Search does not consume email/phone credits (verify enrichment counter stays flat)

Dependencies

Requires APOLLO_API_KEY set in apps/backend/.env.

Screenshot

Screenshot 2026-06-22 at 5 56 58 PM

Rishavraaj and others added 3 commits June 22, 2026 12:37
…dpoints

- Add SearchProspectsDto and AddPeopleToSequenceDto with class-validator
- Add ApolloProspectsService:
  - searchPeople(): POST /mixed_people/search with name, title, location,
    org filters; deduplicates contacts/people from Apollo response
  - searchOrganizations(): GET /mixed_companies/search for company autocomplete
  - addPeopleToSequence(): converts raw Apollo person IDs to contacts via
    MCP apollo_contacts_create, then enrolls all via
    apollo_emailer_campaigns_add_contact_ids; creates best-effort Zuko CRM
    records; returns failedPersonIds for partial failures
- Add ApolloProspectsController wiring all three endpoints under
  integrations/apollo/*
- Register controller + service + ContactsRepository in IntegrationsModule

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…pollo API key

Backend:
- Add apollo-prospects.service: searchPeople via mixed_people/api_search
  (free, no enrichment credits), searchOrganizations via accounts/search,
  addPeopleToSequence via MCP apollo_emailer_campaigns_add_contact_ids
- Add SearchProspectsDto with organizationDomains[] field
- Use q_organization_domains_list instead of organization_ids for company
  filter — domains work reliably, send only one at a time to avoid conflicts
- Add ApolloMcpService.listTools() debug helper
- Register ApolloProspectsController + service in IntegrationsModule
- Add person_read + mixed_people_api_search to OAuth scopes list

Frontend:
- AddContactsDialog: increase debounce to 800ms, min 3 chars for name filter
- Pass organizationDomains to search params alongside organizationIds
- Update OrgSearchResult type to include domain field
- Update getProspectSearch query options to support organizationDomains
- Update apollo.ts SearchProspectsParams with organizationDomains

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@anujeet98 anujeet98 merged commit a79c143 into main Jun 23, 2026
2 checks passed
@anujeet98 anujeet98 deleted the feat/prospect-search-backend branch June 23, 2026 05:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants