Contact enrichment is paid per call — whether you're using Apollo, RocketReach, ZoomInfo, or a regional directory like IndiaMART or Amazon.in for India-based prospects. We make it the seventh stage on purpose. Six stages of free research filter the list first, so the credit-card call lands only on leads that have already passed qualification.
lead.fitScore — must clear pack thresholdlead.qualificationTier — must be A or Blead.disqualifiers[] — must be emptypack.targetTitles[] — decision-maker titles to query for (e.g. Head of People, VP Engineering)pack.enrichmentProvider — apollo | rocketreach | zoominfo | indiamart | amazon_in | customworkspace.enrichmentKey — your provider key, your accountcontacts[].verifiedEmail — provider-verified deliverable addresscontacts[].title — current job titlecontacts[].seniority — c_suite | vp | director | manager | iccontacts[].linkedinUrlcontacts[].phone — when availablecontacts[].departmentMatch — match against pack's target deptsenrichment_data.creditsUsed — billed-to-you on this leadenrichment_data.enrichedAt — timestamp + operator idif (!lead.fitScore || lead.fitScore < pack.minFit) return refuse("not_qualified"); if (lead.disqualifiers.length > 0) return refuse("disqualified"); if (lead.enrichment_data?.enrichedAt) return refuse("already_enriched"); return enrichment.fetch({ domain: lead.domain, titles: pack.targetTitles, cap: pack.maxContactsPerLead });
Contact enrichment is the first stage that costs real money. Every other stage is either a free read (web fetch, LinkedIn public scrape via Sonar) or a sub-cent LLM token spend. Most enrichment providers charge per credit, and each lead burns one to several credits depending on how many contacts you pull. We make this a deliberate human click rather than an automatic pipeline step. The qualification stage above it is the filter that decides whether this lead is worth the call.
The pack declares the titles you want. The recruiting pack queries the provider for VP People, Head of Talent, People Operations Lead. The fintech pack asks for Head of Risk, Compliance Lead, VP Finance. The provider returns a ranked list of contacts at the company matching those titles, deduplicated against any contacts already enriched on this lead in the past. The cap is set per pack — typically three contacts per lead, sometimes one for high-credit-cost packs.
Pluggable providers, region-aware. Use Apollo or RocketReach or ZoomInfo for global B2B titles. Switch to IndiaMART or an Amazon.in seller-directory scan when the pack is targeting Indian manufacturers and the names you need don't show up on LinkedIn. Each provider runs against your own account, your own API key, your own bill — Paitho does not resell credits. The workspace stores your key encrypted at rest, and the operator clicking the button sees the per-call credit estimate before the request fires. If your account hits its monthly cap, the button disables across the workspace until the quota resets — leads queue up in the awaiting_enrichment column until then.
--- request (provider-agnostic shape) --- POST {{provider.endpoint}} # apollo.io · rocketreach.co · zoominfo · indiamart · custom headers: X-Api-Key: {{workspace.enrichmentKey}} Content-Type: application/json body: { "organization_domains": ["{{lead.domain}}"], "person_titles": {{pack.targetTitles | json}}, "person_seniorities": ["c_suite","vp","director","manager"], "reveal_personal_emails": false, "max_results": {{pack.maxContactsPerLead}} } --- response (mapped to a unified shape across providers) --- { "contacts": [ { "name": string, "title": string, "seniority": "c_suite"|"vp"|"director"|"manager"|"ic", "verifiedEmail": string, # provider-verified deliverable "linkedinUrl": string|null, "phone": string|null, "departmentMatch": boolean, "sourceProvider": string # which provider returned this row } ], "creditsUsed": int, "enrichedAt": iso8601, "operatorId": uuid } --- guards --- - One enrichment per lead per 30 days unless force-reenrich is checked. - creditsUsed is shown to the operator before the click. - Failed verification → contact is dropped, not stored as a guess. # <!-- PLACEHOLDER — exact field mapping in app config -->
Lead enriches before qualification finishes; credits spent on a lead that turns out disqualified.
Server-side guard refuses the call unless fitScore is above pack threshold and disqualifiers is empty. The button is disabled in the UI as well.
Same lead enriches twice across reps; double-billed.
30-day per-lead lockout. Force-reenrich requires admin confirmation showing prior enrichment date and previous contacts.
The provider's verification flags an address as good but it bounces on send.
Bounces auto-tag the contact email_invalid and feed back into the pack's accuracy stats. Address is suppressed across the workspace.
See the per-lead credit estimate. Click only on leads worth the call.