Connect ContactOut to AI Agents: Automate Prospecting and Data Sourcing
Give your AI agent ContactOut tools.
Give your AI agents secure, programmatic access to ContactOut. We cover how to fetch tools, handle asynchronous bulk enrichment, manage API credits, and build resilient multi-step workflows.
In this guide
- 01Establish Your Agent Framework
- 02Fetch Tools from the Truto API
- 03Bind Tools to the LLM
- 04Implement Rate Limit Backoff
- 05Test the Workflow
The guide
Learn how to connect ContactOut to AI agents using Truto's /tools endpoint. Build autonomous workflows for prospecting, data sourcing, and profile enrichment.
You want to connect ContactOut to an AI agent so your system can independently discover decision makers, enrich contact profiles, verify emails, and orchestrate outbound prospecting workflows. Here is exactly how to do it using Truto's /tools endpoint and SDK, bypassing the need to build and maintain a custom integration from scratch.
Giving a Large Language Model (LLM) read and write access to a powerful data sourcing platform like ContactOut is an engineering challenge. If you give an agent raw API access, it is prone to hallucinate query parameters, ignore pagination, and rapidly drain your API credits by looping over the wrong endpoints. If your team uses ChatGPT, check out our guide on connecting ContactOut to ChatGPT, or if you are building on Anthropic's models, read our guide on connecting ContactOut to Claude. For developers building custom autonomous workflows, you need a programmatic way to fetch these tools and bind them to your agent framework.
This guide breaks down exactly how to fetch AI-ready tools for ContactOut, bind them natively to an LLM using frameworks like LangChain, LangGraph, CrewAI, or the Vercel AI SDK, and execute complex revenue operations workflows. For a deeper look at the architecture behind this approach, refer to our research on architecting AI agents and the SaaS integration bottleneck.
Why a Unified Tool Layer Matters for Agent Safety
Before writing integration code, you must decide what layer your agent talks to. This choice determines the safety, cost efficiency, and reliability of your production system.
Direct API tools - writing one custom function per raw ContactOut endpoint - seem convenient for prototypes. But in production, you force the LLM to understand vendor-specific quirks. The model has to remember exactly which payload structure is required for V1 bulk enrichment versus V2 asynchronous enrichment, or exactly which combination of parameters is valid for a decision-maker search. Every quirk you push into the LLM context window is a hallucination risk.
A unified tool layer collapses these complexities behind a standardized schema. Your agent sees simple, descriptive functions with strict JSON inputs. That gives you concrete engineering wins:
- Deterministic input validation. Every tool has a strict JSON schema. Invalid arguments are rejected before they hit the ContactOut API, preventing wasted requests and errors.
- Credit preservation. By standardizing the tool names and descriptions, you can explicitly guide the LLM to use zero-credit verification tools before executing high-cost enrichment tools.
- Smaller attack surface. The LLM only chooses from a controlled set of methods, rather than attempting to guess REST paths or HTTP verbs.
The Engineering Reality of the ContactOut API
ContactOut provides high-value intelligence data. Because this data is expensive to source and maintain, their API has specific operational constraints designed to protect their infrastructure and billing models. If you hardcode these interactions into your agent, you will spend your sprints writing defensive code instead of improving your model's reasoning capabilities.
Here are the specific realities of the ContactOut API that you must account for when building agentic workflows.
The Credit Consumption Trap
Unlike a typical CRUD API (like a CRM) where you simply pay for a software license and API calls are essentially free, ContactOut operates on a granular credit model. Different endpoints consume different types of credits - search credits, email credits, phone credits, and verifier credits.
For example, calling the primary enrichment endpoint costs 1 search credit per profile found, plus 1 email or phone credit when that data is found. If an autonomous agent decides to iteratively loop through a list of 5,000 low-quality LinkedIn URLs to find a specific title, it will instantly decimate your API budget.
To build a safe agent, you must provide the LLM with intermediate tools. ContactOut offers specific endpoints that do not consume credits, such as checking if a personal email, work email, or phone number exists on a profile. Your agent orchestration layer must force the LLM to use these verification tools first, and only proceed to the paid enrichment tool if a positive boolean is returned.
The Synchronous vs Asynchronous Bulk Divide
Agents working in revenue operations frequently handle bulk lists. ContactOut splits bulk enrichment into two distinct architectural patterns:
- V1 Bulk: Synchronous calls for up to 100 LinkedIn profiles. The HTTP request holds open until the data is returned.
- V2 Bulk: Asynchronous jobs for up to 1000 profiles. The API immediately returns a
job_idwith aQUEUEDstatus.
LLMs struggle immensely with asynchronous architectures. Standard LLMs execute sequentially and expect immediate data in the tool response. If an agent receives a job_id, it will often hallucinate the actual data, assuming the job is already complete. You must provide your agent with two separate tools: one to create the job, and another explicitly named tool to retrieve the job by its ID. You then have to prompt the LLM to enter a polling loop, or handle the polling via a state machine like LangGraph before passing control back to the LLM.
Strict Rate Limiting and 429 Propagation
The ContactOut API enforces strict rate limits, often capping requests to 60 per minute for certain endpoints. When an LLM executes tools in parallel (such as enriching a list of 20 decision makers simultaneously), you will hit this limit almost immediately.
Critical infrastructure note: Truto handles authorization, pagination, and schema mapping, but Truto does not retry, throttle, or apply backoff on rate limit errors. When ContactOut returns an HTTP 429 error, Truto passes that exact error back to the caller.
Truto normalizes the upstream rate limit information into standard IETF headers:
ratelimit-limitratelimit-remainingratelimit-reset
Your agent execution loop is strictly responsible for inspecting these headers, pausing execution until the ratelimit-reset timestamp, and re-executing the tool call. Do not assume the integration layer will absorb 429 errors for you.
Fetching Tools Programmatically
To bind ContactOut capabilities to your agent, you need to pull the tool schemas into your application. Truto provides a dedicated endpoint GET /integrated-account/<id>/tools that returns an array of JSON objects describing every available method, properly formatted for LLM function calling.
If you are using Node.js and LangChain, the truto-langchainjs-toolset package handles this mapping natively.
import { ChatOpenAI } from "@langchain/openai";
import { TrutoToolManager } from "@trutohq/truto-langchainjs-toolset";
async function initializeAgent() {
// 1. Initialize the tool manager with your Truto API key
const toolManager = new TrutoToolManager({
apiKey: process.env.TRUTO_API_KEY
});
// 2. Fetch the tools for a specific integrated ContactOut account
const integratedAccountId = "your-contactout-account-id";
const tools = await toolManager.getTools(integratedAccountId);
// 3. Initialize your LLM
const llm = new ChatOpenAI({
modelName: "gpt-4o",
temperature: 0
});
// 4. Bind the ContactOut tools natively to the LLM
const llmWithTools = llm.bindTools(tools);
return llmWithTools;
}Because the /tools endpoint serves dynamic schemas based on how you have configured the integration in the Truto interface, any changes you make to descriptions or parameter requirements propagate immediately to your agent.
ContactOut Hero Tools
Below are high-leverage tools available for ContactOut. These tools represent the core operations required to build autonomous prospecting agents.
Search Decision Makers
Tool name: contact_out_people_search_decision_makers
Instead of broad searches, this tool specifically targets decision makers at a target company. It requires at least one identifier - a LinkedIn URL, domain, or exact name. This prevents the LLM from making overly ambiguous searches that return noisy data and waste credits.
"Find the decision makers at the company with the domain 'acme-corp.com'. Retrieve the first page of results."
Check Work Email Existence
Tool name: contact_out_contacts_check_work_email
This is a critical safety tool for managing your API budget. It checks whether ContactOut has a work email on file for a specific LinkedIn profile, returning a simple boolean and the verification status (Verified, Unverified, or null). It does not consume your paid credits, allowing the agent to filter leads aggressively before spending money.
"Before running a full enrichment, check if ContactOut has a work email on file for the LinkedIn profile URL 'linkedin.com/in/johndoe'."
Enrich People Profiles
Tool name: contact_out_people_enrich
This is the core data retrieval tool. It enriches a single person based on a LinkedIn URL, email, phone, or a combination of name and company data. The agent can use this to flesh out a bare-bones lead record pulled from your CRM.
"Enrich the profile for the email 'jane.smith@acme-corp.com'. Return the full profile data including any available phone numbers."
Enrich Companies
Tool name: contact_out_companies_enrich
For Account-Based Marketing (ABM) workflows, the agent needs firmographic context. This tool accepts up to 30 domains at once and returns structured company details, allowing the agent to qualify accounts before searching for individual people.
"Retrieve the firmographic details, including employee count and industry, for 'acme-corp.com' and 'globex.com'."
Create Async Bulk Enrichment Job
Tool name: create_a_contact_out_contact_enrichment_job
When the agent needs to process massive lists (up to 1000 URLs), synchronous calls will time out. This tool creates a V2 bulk job. The agent must be instructed to save the resulting job_id.
"Create a bulk contact enrichment job for the provided list of 500 LinkedIn URLs. Save the job ID for the next step."
Retrieve Async Bulk Enrichment Job
Tool name: get_single_contact_out_contact_enrichment_job_by_id
This tool retrieves the status and results of a V2 bulk job. The agent will use the job_id obtained in the previous step. If the status is not DONE, the agent execution loop must handle waiting and retrying.
"Check the status of the enrichment job with ID 'job-abc-123'. If the status is DONE, summarize the retrieved emails."
Verify Email Deliverability
Tool name: contact_out_email_verifications_verify
Before an agent passes a lead to an outbound sequencer, it must ensure the email won't bounce and damage your domain reputation. This tool checks a single email address and returns a strict status (valid, invalid, accept_all, disposable, or unknown).
"Verify the deliverability of 'j.smith@acme-corp.com'. Only proceed with drafting the outreach message if the status is strictly 'valid'."
Workflows in Action
Combining these tools allows you to build sophisticated, multi-step orchestration workflows that operate entirely autonomously.
Scenario 1: Autonomous Account-Based Expansion
A user wants the agent to take a target domain, find the right people, verify their contact info without wasting credits, and prepare them for outreach.
"Take the domain 'stellar-tech.io'. Find their decision makers. For each decision maker, check if a work email exists on file (without using credits). If it does, run a full enrichment to get the actual email, then verify its deliverability."
- The agent calls
contact_out_companies_enrichto gather firmographic context on stellar-tech.io to ensure it fits the ideal customer profile. - The agent calls
contact_out_people_search_decision_makerspassing the domain to retrieve a list of top-level LinkedIn URLs. - For each URL, the agent calls
contact_out_contacts_check_work_email. This costs zero credits. - The agent filters out profiles that returned
false. - For the remaining profiles, the agent calls
contact_out_people_enrichto spend the necessary credits and retrieve the actual work email strings. - The agent iterates through the retrieved emails, calling
contact_out_email_verifications_verify. - The user receives a finalized, highly filtered list of confirmed valid emails for verified decision makers, fully protecting the API budget and domain sender reputation.
Scenario 2: Processing Historic CRM Deficiencies
A user has hundreds of old CRM records that only contain names and company names, and wants the agent to process them in bulk.
"I have a list of 300 names and companies. Find their LinkedIn profiles, then trigger a bulk job to find their personal emails. Tell me when it is finished."
- The agent iterates through the list, calling
contact_out_people_enrich(using the name/company parameters) to extract the officiallinkedin_urlfor each record. - Once the URLs are compiled, the agent calls
create_a_contact_out_contact_enrichment_jobpassing the massive list to the V2 bulk endpoint. - The agent receives a
job_idwith aQUEUEDstatus. - The agent execution loop enters a waiting pattern. After an interval, it calls
get_single_contact_out_contact_enrichment_job_by_id. - Once the API returns a
DONEstatus, the agent parses the payload, extracting thepersonal_emailsarrays for each matched profile, and returns the structured data to the user.
Building Multi-Step Workflows
When building an agent execution loop - regardless of whether you use LangChain, LangGraph, or a custom script - you must handle the mechanics of tool execution and error handling.
Because Truto normalizes upstream errors, including rate limits, your execution layer must catch 429 status codes, read the ratelimit-reset header, and back off.
Here is a conceptual flow of how a resilient execution loop operates:
sequenceDiagram
participant Agent as LLM Agent
participant Runner as Execution Loop
participant Truto as Truto API
participant CO as ContactOut API
Agent->>Runner: Emits Tool Call (contact_out_people_enrich)
Runner->>Truto: POST /proxy/contact_out/enrich
Truto->>CO: Request Data
CO-->>Truto: 429 Too Many Requests
Truto-->>Runner: 429 Error + ratelimit-reset header
Runner->>Runner: Parse header, pause execution for X seconds
Runner->>Truto: Retry POST /proxy/contact_out/enrich
Truto->>CO: Request Data
CO-->>Truto: 200 OK (Profile Data)
Truto-->>Runner: JSON Payload
Runner-->>Agent: Return Tool MessageIn code, this requires inspecting the headers on failure. If you are using the TrutoToolManager, tools are invoked dynamically. You should wrap your agent invocation in a retry utility.
import pRetry from 'p-retry';
// A generic tool execution wrapper that respects the Truto rate limit headers
async function executeToolWithBackoff(toolCall, toolManager) {
return pRetry(
async () => {
try {
// Execute the tool call generated by the LLM
const result = await toolManager.execute(toolCall);
return result;
} catch (error) {
// Inspect for HTTP 429 and standard rate limit headers
if (error.status === 429 && error.headers) {
const resetTimeStr = error.headers.get('ratelimit-reset');
if (resetTimeStr) {
const resetTimeMs = parseInt(resetTimeStr, 10) * 1000;
const now = Date.now();
const waitTime = Math.max(0, resetTimeMs - now);
console.warn(`Rate limited by ContactOut. Waiting ${waitTime}ms.`);
// Throw a specific error that p-retry can catch to trigger a delayed retry
throw new Error(`RATE_LIMIT:${waitTime}`);
}
}
// If it's a 400 bad request or other error, do not retry, fail fast.
throw new pRetry.AbortError(error.message);
}
},
{
retries: 3,
onFailedAttempt: async error => {
if (error.message.startsWith('RATE_LIMIT:')) {
const waitTime = parseInt(error.message.split(':')[1], 10);
await new Promise(resolve => setTimeout(resolve, waitTime));
}
}
}
);
}By unifying your tools through Truto and implementing resilient execution logic, you transform a fragile script into an autonomous system. Your agent no longer has to guess at JSON:API specifications, stumble over pagination cursors, or hallucinate credit-draining requests. It simply calls deterministic functions, reads standard JSON outputs, and focuses entirely on reasoning through your revenue operations pipelines.
FAQ
- How do I prevent my AI agent from draining ContactOut credits?
- Provide your agent with zero-credit checking tools first, such as contact_out_contacts_check_personal_email. Instruct the LLM in its system prompt to verify data existence before executing credit-consuming enrichment endpoints.
- Does Truto automatically handle ContactOut rate limits?
- No. When ContactOut returns an HTTP 429 error, Truto passes that error directly to the caller. Truto normalizes the upstream headers into standardized ratelimit-limit, ratelimit-remaining, and ratelimit-reset headers. Your agent execution loop must handle the retry and backoff logic.
- Can I use these ContactOut tools with LangGraph?
- Yes. Truto exposes tools via standard JSON Schema formats. You can bind them directly to any framework, including LangChain, LangGraph, CrewAI, or the Vercel AI SDK using the .bindTools() method.
- How do I handle bulk enrichment asynchronously with an LLM?
- Give the LLM access to the V2 bulk job creation tool and the job status retrieval tool. You must instruct the agent to create the job, extract the job_id, and either pause execution until a webhook fires, or poll the status endpoint iteratively.