Apollo.io ExecModule
Overview
ApolloModule connects ValkyrAI workflows to Apollo's current sales-intelligence API for bounded prospect and organization research, contact management, and API-usage inspection. It exposes nine operations through the native map I/O ExecModule ABI and keeps the API key in a READY IntegrationAccount.
The module fixes the production origin to https://api.apollo.io/api/v1, sends API-user credentials only in x-api-key, bounds request and response sizes, rejects credential-like payload fields, returns one search page per execution, retries transient read operations only, and sends contact writes once. Organization search and enrichment operations require allowCreditUse: true because Apollo plan credits may be consumed.
n8n's Apollo-based lead-generation and enrichment workflows informed the composable search-to-contact flow. ValkyrAI adds a generated IntegrationAccount boundary, explicit credit consent, fixed-origin enforcement, provider-identity checks, bounded output, write reconciliation, and shared credential redaction.
Usage
- Create an Apollo API key with only the scopes needed for the chosen operations.
- Store the key only in the encrypted
apiKeyfield of a ValkyrAIIntegrationAccount, set the account toREADY, and bind it throughExecModuleConfig.authConfig.integrationAccount. - Choose one operation and provide its conditional fields.
- For
search_people,search_organizations, orsearch_contacts, passnextPageinto a later execution whenhasMoreistrue. - Before
search_organizations,enrich_person, orenrich_organization, review the Apollo workspace's plan and credit balance, then setallowCreditUse: trueonly when the spend is approved. - Keep outbound messages and bulk sequence enrollment behind separate human approval. This module does not send outreach.
Inputs
| Name | Type | Required | Description | Constraints |
|---|---|---|---|---|
operation | string | Yes | Operation listed below. | Exact allowlist of nine values. |
recordId | string | Conditional | Apollo contact ID for get_contact and update_contact. | 6–128 letters, digits, _, or -. |
params | object | Conditional | Search or enrichment filters. | At most 20 allowlisted fields; arrays contain 1–100 scalar values; each value is at most 2,048 characters. |
record | object | Conditional | Contact fields for create/update. | Non-empty, at most 20 top-level fields and 256 KiB serialized; credential-like fields rejected. |
page | integer | No | One-based provider page. | 1–500; default 1. |
perPage | integer | No | Provider page size. | 1–100; default 25. |
allowCreditUse | boolean | Conditional | Explicit acknowledgement for potentially credit-consuming calls. | Must be true for organization search and enrichment operations. |
People search supports bounded job-title, seniority, keyword, person/company location, company-domain, email-status, organization ID, employee-range, and technology filters. Organization search supports domain, employee range, included/excluded location, technology, keyword, name, and ID filters. Person enrichment accepts identity fields such as name, business email, company/domain, Apollo ID, or LinkedIn URL. Organization enrichment accepts domain, LinkedIn URL, name, or website.
Contact search supports keywords, stage IDs, label IDs, and documented sorting. Contact writes allow first/last name, employer, title, account ID, email, website, labels, stage, address, phone fields, typed custom fields, and run_dedupe. create_contact requires an email, first name, or last name.
Outputs
| Name | Type | When present | Description |
|---|---|---|---|
status | string | Always | success or error. |
operation | string | Always | Normalized operation. |
data | object | Single-record or usage success | Verified Apollo object or usage payload. |
id | string | Single-record success | Positive provider identity from the response. |
items | array | Search success | One bounded provider page. |
count | integer | Search success | Items returned in this page. |
page | integer | Search success | Current one-based page. |
total | integer | When Apollo supplies it | Provider-reported total entries. |
hasMore | boolean | Search success | Whether another page may exist. |
nextPage | integer | When another page exists | Page for the next execution. |
creditUseApproved | boolean | After governance validation | Whether the caller approved possible credit use. |
attempts | integer | Provider call or error | HTTP attempts consumed. |
error | object | Failure | Redacted code, message, and retryable fields. |
Prospect, organization, and contact responses are classified restricted. API keys and provider bodies are never copied into progress logs.
IntegrationAccount Requirements
| Setting | Requirement |
|---|---|
| Provider | Apollo API v1 |
| Authentication | Apollo API key in the x-api-key header |
| Status | Exactly READY |
accountName | Human-readable Apollo workspace/key identity |
apiKey | Encrypted API key, 16–2,048 non-whitespace characters |
| Relationship | ExecModuleConfig.authConfig.integrationAccount |
| Suggested scopes | Only the selected search, enrichment, contact read/write, or usage scopes |
API keys must not be passed as Bearer tokens. Apollo partners can implement OAuth separately, but this version intentionally uses the established API-user key contract and does not implement OAuth application lifecycle or refresh.
Configuration
Illustrative persisted configuration:
{
"version": "1.0.0",
"authConfig": {
"authStrategy": 1,
"integrationAccount": "integration-account:apollo-revenue-research"
},
"payloadConfig": {
"parameters": "{\"operation\":\"search_people\",\"page\":1,\"perPage\":25,\"params\":{\"person_titles\":[\"VP Engineering\"],\"person_seniorities\":[\"vp\"]}}"
}
}
The relationship is symbolic. The generated IntegrationAccount record owns the encrypted key.
Operations
| Operation | Apollo path | Behavior | Credit acknowledgement |
|---|---|---|---|
search_people | POST /mixed_people/api_search | Search net-new prospects; email and phone reveal are not exposed. | No local acknowledgement required; review the current plan. |
search_organizations | POST /mixed_companies/search | Search companies with bounded filters. | Required; Apollo documents per-page credit use. |
enrich_person | POST /people/match | Match one person from bounded identity fields. | Required; returned enrichment can consume credits. |
enrich_organization | GET /organizations/enrich | Match one company from domain/name/URL. | Required; returned enrichment can consume credits. |
search_contacts | POST /contacts/search | Search contacts already saved in the workspace. | No. |
create_contact | POST /contacts | Create one contact; run_dedupe: true is supported. | No; write is single-attempt. |
get_contact | GET /contacts/{contactId} | Read one saved contact and verify its ID. | No. |
update_contact | PATCH /contacts/{contactId} | Update one saved contact and verify its ID. | No; write is single-attempt. |
api_usage | POST /usage_stats/api_usage_stats | Inspect plan-specific endpoint usage and limits. | No. |
Account/opportunity/list/note administration, sequence enrollment, email sending, calls, tasks, conversations, webhook administration, bulk writes, waterfall enrichment, personal-email reveal, and phone reveal are deferred. Those surfaces have materially different billing, privacy, or outbound-action risks.
Errors and Failure Modes
| Failure | Cause | Retry guidance |
|---|---|---|
VALIDATION_ERROR | Missing field, invalid ID/filter/bound, disallowed reveal field, absent credit acknowledgement, unsafe write key, or invalid provider response. | Correct the request; local validation sends no provider call. |
INTEGRATION_ACCOUNT_REQUIRED | No bound secure account. | Bind the intended Apollo account. |
INTEGRATION_ACCOUNT_NOT_READY | Account status is not READY. | Repair or reauthorize the account. |
APOLLO_HTTP_401 | Missing/invalid API key or Bearer-style misuse. | Rotate the key and keep it in x-api-key. |
APOLLO_HTTP_403 | Plan or key scope does not include the endpoint. | Grant only the required scope or choose a supported plan. |
APOLLO_HTTP_422 | Provider validation, missing record, or incompatible filter. | Correct IDs or field shapes; do not blindly retry. |
APOLLO_HTTP_429 | Fixed-window endpoint limit exceeded. | Reads use bounded retry and numeric Retry-After; contact writes remain single-attempt. |
APOLLO_HTTP_5xx / NETWORK_ERROR | Provider or transport failure. | Safe reads retry up to three total attempts. Reconcile create/update state before manual retry. |
RESPONSE_TOO_LARGE | Provider response exceeded 5 MiB. | Narrow filters or page size. |
Provider errors are bounded to 500 characters and pass through API-key replacement plus the shared sensitive-data policy. A failed contact write may have reached Apollo, so the module refuses automatic replay.
Example
Find senior engineering leaders at one approved company:
{
"operation": "search_people",
"page": 1,
"perPage": 25,
"params": {
"person_titles": ["VP Engineering", "Chief Technology Officer"],
"person_seniorities": ["vp", "c_suite"],
"q_organization_domains_list": ["example.com"]
}
}
Expected normalized result:
{
"status": "success",
"operation": "search_people",
"items": [
{
"id": "person_123",
"name": "Ada Lovelace",
"title": "VP Engineering"
}
],
"count": 1,
"page": 1,
"total": 1,
"hasMore": false,
"creditUseApproved": false,
"httpStatus": 200,
"attempts": 1
}
Notes
- Pagination: one execution returns one page. Reuse
nextPage; no silent all-pages loop occurs. Apollo search display limits can be lower than the theoretical page range, so narrow filters instead of attempting exhaustive scans. - Rate limits: Apollo uses fixed per-endpoint windows whose minute/hour/day limits depend on the plan.
api_usageexposes current workspace values. The module treats429as transient for reads and caps retries to three attempts. - API and credit limits: local pages are capped at 500, page size at 100, request JSON at 256 KiB, and responses at 5 MiB. Organization search is documented as consuming credits per page; enrichment can consume credits when qualifying data is returned. Always review live Apollo pricing before scaling.
- Idempotency: searches, reads, enrichment lookups, and usage inspection are retry-safe at the transport level but repeated enrichment can consume credits. Contact create/update calls are single-attempt.
run_dedupe: truecan match and update an existing contact; it is not a no-op guarantee. - Destructive behavior: deletion and bulk mutation are intentionally not exposed. Contact create/update can still alter CRM ownership, labels, stages, automations, and downstream integrations.
- Privacy and outreach: prospect/contact output is restricted. The module does not reveal personal emails or phone numbers, enroll contacts in sequences, or send messages. Apply lawful-basis, consent, suppression, and human-review controls before outreach.
- External verification: deterministic tests cover validation, request construction, repeated query arrays,
x-api-keyauthentication, pagination, credit acknowledgement, transient read retries, write non-retry, redaction, identity checks, fixed origin, response normalization, and metadata discovery. Live provider execution is deferred until a separately authorized Apollo workspace and API key are supplied.
See the official Apollo API overview, authentication contract, People API Search, Organization Search, contact creation, rate limits, credit policy, and an n8n Apollo lead workflow for upstream behavior and functional reference.