How to Connect Affinity to AI Agents: Tool Calling & Workflow Automation
Learn how to connect Affinity to AI agents using Truto's /tools endpoint. Bind Affinity APIs to LangChain or LangGraph for autonomous CRM workflows.
A February 2026 Gartner survey revealed that 91% of sales and customer service leaders are under intense executive pressure to implement AI. The business mandate is clear: automate CRM hygiene, reduce manual data entry, and surface relationship intelligence directly within conversational interfaces. Giving a Large Language Model (LLM) read and write access to your Affinity instance is an engineering challenge.
Building AI agents is easy. Connecting them to external SaaS APIs is hard. Giving an LLM access to external data sounds simple in a prototype: you write a Node.js function that makes a fetch request and wrap it in an @tool decorator. In production, this approach collapses entirely.
If you decide to build a custom integration for Affinity, you are responsible for the entire API lifecycle. You have to handle OAuth token refreshes or secure API key management. You have to write and maintain massive JSON schemas for every endpoint you want the LLM to access. When the LLM requests a list of interactions, you have to write the logic to handle pagination cursors.
You either spend weeks building, hosting, and maintaining a custom connector, or you use a managed infrastructure layer that handles the boilerplate for you. This guide breaks down exactly how to use Truto's /tools endpoint to generate AI-ready tools for Affinity, bind them natively to your LLM using LangChain, and execute complex CRM workflows autonomously.
The Engineering Reality of Custom Affinity Connectors
Affinity is a relationship intelligence platform. It tracks emails, meetings, deal stages, and complex interpersonal networks. To build an AI agent capable of summarizing an account or updating a deal stage, the agent needs to chain multiple API calls together.
Rate Limits and Edge Cases
Affinity enforces specific rate limits. If your AI agent gets stuck in a loop or tries to summarize hundreds of interactions at once, the API will return a 429 error. Your infrastructure needs exponential backoff, circuit breakers, and retry logic. Through Truto, those 429 responses include normalized rate limit headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) so your stack can read consistent values across providers. If the LLM hallucinates an ID format, the API rejects the request, and the agent needs explicit error feedback to correct its parameters.
Pagination Blindness
LLMs do not inherently understand cursor-based pagination. If an agent asks for a list of contacts and the API returns the first 50 results with a next_cursor, the LLM will often ignore the cursor and assume those 50 contacts are the entire database. You have to explicitly instruct the LLM via the tool description to pass the cursor value back unchanged in subsequent calls.
Authentication State OAuth tokens expire. If an agent tries to update a deal stage and the token has expired, the request fails. Your system needs to proactively refresh tokens shortly before they expire, ensuring the agent never encounters an auth error mid-workflow.
The Solution: Dynamic Tool Generation via Truto
Instead of manually writing JSON schemas and @tool decorators for every Affinity endpoint, you can use Truto. Truto normalizes data across hundreds of SaaS platforms and provides a generic execution pipeline.
Every integration on Truto is represented as a comprehensive configuration object that maps the underlying product's API behavior. Truto automatically translates these resource definitions into LLM-compatible tools. By calling the Truto /tools endpoint, you instantly receive an array of fully defined tools complete with descriptions, query schemas, and body schemas.
What is an LLM Tool? A tool is a callable operation exposed to an AI agent (e.g., "list all Affinity contacts"). It contains a name, a human-readable description telling the LLM when to use it, and a strict JSON Schema defining the required inputs.
How Truto Handles the Boilerplate
- Authentication: Truto manages the OAuth lifecycle or API keys. It proactively refreshes credentials shortly before they expire, ensuring API calls always succeed.
- Pagination: For
listmethods, Truto automatically injectslimitandnext_cursorproperties into the tool schema. The schema explicitly instructs the LLM: "Always send back exactly the cursor value you received without decoding or modifying it." - Method Filtering: You can restrict the tools an agent has access to. By passing
methods [0]=readto the tools endpoint, you generate a read-only agent that cannot accidentally delete records.
Step-by-Step: Connecting Affinity to LangChain
Let's walk through how to fetch these tools and bind them to an agent using the Truto LangChain.js SDK. This approach works identically for LangGraph, Vercel AI SDK, or custom agent loops.
1. Fetch the Tools
First, connect an Affinity account via the Truto interface to get an integrated_account_id. Then, initialize the TrutoToolManager.
import { TrutoToolManager } from '@truto/langchainjs-toolset';
import { ChatOpenAI } from '@langchain/openai';
import { createOpenAIToolsAgent, AgentExecutor } from 'langchain/agents';
// Initialize the tool manager for the specific Affinity account
const toolManager = new TrutoToolManager({
integratedAccountId: 'your_affinity_integrated_account_id',
trutoApiKey: process.env.TRUTO_API_KEY,
});
// Fetch all available Affinity tools
const tools = await toolManager.getTools();2. Bind Tools to the LLM
Once you have the tools, bind them to your model. The LLM now knows exactly what endpoints exist, what they do, and what parameters they require.
const llm = new ChatOpenAI({
modelName: 'gpt-4o',
temperature: 0,
});
// Bind the Truto tools to the LLM
const llmWithTools = llm.bindTools(tools);3. Execute the Agentic Workflow
Now you can ask the agent to perform complex workflows. The agent will autonomously determine which tools to call, execute them, and synthesize the result.
const response = await llmWithTools.invoke(
"Find the organization 'Acme Corp' in Affinity. Then, list all recent interactions with them, and draft a short summary note. Finally, create a new note in Affinity with that summary."
);
console.log(response);Agent Architecture Visualization
When you run the code above, the execution flow looks like this:
sequenceDiagram
participant User
participant Agent as AI Agent (LangGraph)
participant Truto as Truto /tools API
participant Affinity as Affinity API
User->>Agent: "Summarize interactions for Acme Corp"<br>and save as a note.
Agent->>Truto: Call list_all_affinity_organizations (Tool)
Truto->>Affinity: GET /organizations?term=Acme
Affinity-->>Truto: Raw JSON
Truto-->>Agent: Normalized schema + Org ID
Agent->>Truto: Call list_all_affinity_interactions (Tool)<br>using Org ID
Truto->>Affinity: GET /interactions?organization_id=123
Affinity-->>Truto: Raw JSON
Truto-->>Agent: Normalized interactions
Agent->>Truto: Call create_a_affinity_note (Tool)
Truto->>Affinity: POST /notes
Affinity-->>Truto: Note ID
Truto-->>Agent: Success confirmation
Agent-->>User: "Summary created and saved to Affinity."Full Inventory of Affinity AI Agent Tools
Truto automatically generates over 50 specific tools for the Affinity API. By exposing these to your agent, you grant it total programmatic control over your CRM data.
For the complete, up-to-date schema definitions, visit the Affinity integration page.
Interactions & Notes
Interactions and notes are the lifeblood of relationship intelligence. These tools allow agents to read historical context and log new meeting summaries.
- create_a_affinity_interaction: Create a new interaction in Affinity with required parameters type, person_ids, content, and date.
- list_all_affinity_interactions: List interactions in Affinity filtered by type, start_time, and end_time. Returns key interaction fields.
- get_single_affinity_interaction_by_id: Get details for a specific interaction in Affinity. Requires id and type. Returns fields including date and content.
- update_a_affinity_interaction_by_id: Update an existing interaction in Affinity using id, type, and person_ids. Returns updated interaction fields.
- delete_a_affinity_interaction_by_id: Delete a specific interaction in Affinity using id and type. Returns confirmation of successful deletion.
- create_a_affinity_note: Create a new note in Affinity. Requires content. Returns id and association details.
- list_all_affinity_notes: List all notes in Affinity. Returns key fields including creator_id and associated entities.
- get_single_affinity_note_by_id: Get a specific note in Affinity using id. Returns creator_id, content, and person/org associations.
- update_a_affinity_note_by_id: Update a specific note in Affinity by id with new content. Requires id and content.
- delete_a_affinity_note_by_id: Delete a note in Affinity using id. Removes the specified note permanently.
Persons & Organizations
Agents can autonomously enrich profiles, update contact details, or pull relationship strength scores before drafting outreach emails.
- create_a_affinity_person: Create a new person in Affinity using first_name, last_name, and emails.
- list_all_affinity_persons: List persons in Affinity that match search criteria. Returns an array of person records.
- get_single_affinity_person_by_id: Get a specific person in Affinity by id. Returns name, primary_email, and associated metadata.
- update_a_affinity_person_by_id: Update a person in Affinity using id. Returns updated details including name and emails.
- delete_a_affinity_person_by_id: Delete a person in Affinity using id. Removes the person record permanently.
- create_a_affinity_organization: Create a new organization in Affinity by providing name. Returns id and domain details.
- list_all_affinity_organizations: List organizations in Affinity that match search criteria. Returns key fields like organization name and domain.
- get_single_affinity_organization_by_id: Get details about a specific organization in Affinity using id. Returns name, domain, and global fields.
- update_a_affinity_organization_by_id: Update organization with id in Affinity. Returns updated fields such as name and domain.
- delete_a_affinity_organization_by_id: Delete an organization in Affinity using id. Returns confirmation of deletion.
- list_all_affinity_relationship_strength: Get relationship strength in Affinity for a specific external_id. Returns key metrics such as score.
Opportunities & Lists
Automate pipeline management. When an agent detects a positive reply in an email thread, it can automatically move the Opportunity to the next stage in an Affinity List.
- create_a_affinity_opportunity: Create a new opportunity in Affinity with required parameters name and list_id.
- list_all_affinity_opportunities: List opportunities in Affinity that match search criteria. Returns id, name, and associated entities.
- get_single_opportunity_by_id: Get a specific opportunity in Affinity using id. Returns name, person_ids, and organization_ids.
- update_a_affinity_opportunity_by_id: Update an existing opportunity in Affinity using id. Returns modified fields such as name and status.
- delete_a_affinity_opportunity_by_id: Delete an opportunity in Affinity. Requires id. Returns confirmation of deletion status.
- create_a_affinity_list: Create a new list in Affinity with specified name, type, and is_public parameters.
- list_all_affinity_lists: List all lists visible to the user in Affinity. Returns id, name, type, and owner_id.
- get_single_affinity_list_by_id: Get details about a specific list in Affinity using id. Returns attributes like type and public status.
- create_a_affinity_list_entry: Create a new list entry in Affinity. Requires list_id and entity_id. Returns id and creator details.
- list_all_affinity_list_entries: Get all list entries for a specific list_id in Affinity. Returns an array of list entries.
- get_single_affinity_list_entry_by_id: Get a specific list entry by list_id and id in Affinity. Returns id and entity details.
- delete_a_affinity_list_entry_by_id: Delete a specific list entry in Affinity. Requires list_id and id. Returns success status.
Custom Fields & Values
Affinity relies heavily on custom fields. Agents can query field definitions and update specific field values attached to entities.
- create_a_affinity_field: Create a new field in Affinity. Requires name, entity_type, and value_type.
- list_all_affinity_fields: List all fields in Affinity. Returns id, name, list_id, enrichment_source, and value_type.
- list_all_affinity_person_fields: Get global person fields in Affinity. Returns an array of global fields that exist on people.
- list_all_affinity_organization_fields: List all global organization fields in Affinity. Returns id, name, and value_type.
- delete_a_affinity_field_by_id: Delete a specific field in Affinity using id. Returns confirmation of deletion.
- create_a_affinity_field_value: Create a new field value in Affinity using required parameters field_id, entity_id, and value.
- list_all_affinity_field_values: Get all field values attached to a person, organization, opportunity, or list_entry in Affinity.
- update_a_affinity_field_value_by_id: Update a field value in Affinity using id. Requires id. Returns the updated field value object.
- delete_a_affinity_field_value_by_id: Delete a field value in Affinity. Requires id. Returns confirmation of deletion.
- list_all_affinity_field_values_changes: List field-values-changes in Affinity for a specific field using field_id. Returns an array of changes.
Reminders & Files
Give agents the ability to schedule follow-ups or retrieve attached documents for RAG (Retrieval-Augmented Generation) pipelines.
- create_a_affinity_reminder: Create a new reminder in Affinity. Requires owner_id, type, and due_date when type=0.
- list_all_affinity_reminders: List reminders in Affinity filtered by optional parameters like person_id, organization_id, or opportunity_id.
- get_single_affinity_reminder_by_id: Get details of a specific reminder in Affinity using id. Returns id, type, created_at, content, due_date, etc.
- update_a_affinity_reminder_by_id: Update a reminder in Affinity by id. Allows modifying fields such as type, reset_type, reminder_days, etc.
- delete_a_affinity_reminder_by_id: Delete a specific reminder in Affinity. Requires id. Returns confirmation of successful deletion.
- affinity_files_upload: Upload file attachments in Affinity for a specific entity using person_id. Returns uploaded file details.
- list_all_affinity_files: List all files in Affinity. Returns entity_files array containing all files within your organization.
- get_single_affinity_file_by_id: Get a specific file in Affinity using id. Returns details of the entity file including metadata.
- affinity_files_download: Download a specific file in Affinity using id. Returns the actual file corresponding to the id.
- list_all_affinity_whoami: Get information about the authenticated user and their Affinity instance. Returns tenant details.
Moving from Prototype to Production
If you want to build autonomous systems that actually execute workflows across your SaaS stack, you have to solve the integration layer first. Whether you are connecting Affinity to ChatGPT or integrating with Claude, writing point-to-point API connections for your LLMs is a fast track to technical debt.
By leveraging Truto's dynamic tool generation, you abstract away token refreshes and manual schema maintenance for Affinity's API. You get a secure, managed infrastructure layer that provides your agents with normalized, documented, and reliable access to Affinity. When Affinity returns rate limit errors, Truto surfaces them to your caller with normalized rate limit headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset); implement retry logic with exponential backoff in your agent or orchestration layer using those values.
Frequently Asked Questions
- How do I connect Affinity to LangChain?
- You can connect Affinity to LangChain by using an integration layer like Truto to generate LLM-ready tools from the Affinity API, then passing those tools to the agent using the `.bindTools()` method.
- Can AI agents update Affinity deal stages?
- Yes. By exposing the `update_a_affinity_opportunity_by_id` tool to your LLM, the agent can autonomously move deals between stages based on interaction context.
- How do AI agents handle Affinity API pagination?
- An integration layer must explicitly instruct the LLM to pass cursor values back unchanged. Truto handles this automatically in the tool schema definitions injected into the LLM context.