Skip to content

How to Connect AI Agents to Read and Write Data in Salesforce and HubSpot

Learn how to architect bidirectional data flow between AI agents and CRMs like Salesforce and HubSpot without building custom integrations.

Yuvraj Muley Yuvraj Muley · · 10 min read
How to Connect AI Agents to Read and Write Data in Salesforce and HubSpot

If you want to connect an AI agent to read and write data in Salesforce and HubSpot, do not hand the Large Language Model (LLM) two raw vendor APIs and rely on prompt engineering to bridge the gap. You need to place a unified execution layer between your agent and the CRMs. Exposing a narrow set of business-level tools - like find_contact, upsert_account, or list_open_deals - allows that middle layer to absorb the underlying boilerplate of SOQL queries, HubSpot filter groups, OAuth token refreshes, and pagination.

B2B SaaS teams are racing to give LLMs the ability to read and write data in external systems. The demand is not theoretical. Gartner predicts that by 2028, 70% of customer service journeys will begin with conversational AI. But a massive percentage of these agentic AI projects fail in production due to escalating integration costs and inadequate risk controls.

This guide breaks down the architectural patterns, code-level strategies, and infrastructure requirements to safely connect your LLMs to enterprise CRMs for bidirectional data flow, bypassing the engineering tax of custom connectors.

Why Read-Only AI Agents Aren't Enough for CRM

Read-only AI agents retrieve context to answer questions, while read/write AI agents autonomously execute workflows by creating, updating, and deleting records in downstream systems.

Read-only assistants are useful for basic summarization. Read/write assistants are where the business case gets serious. If your agent cannot reliably pull a deal from Salesforce, update the pipeline stage, and log a meeting note in HubSpot, it is just a chatbot with extra steps.

Sales teams using AI see significantly higher revenue growth, driving the business case for read/write CRM agents. Salesforce reports that 83% of sales teams using AI saw revenue growth in the past year, compared to 66% of teams not using AI. According to McKinsey, generative AI can reduce the time spent on customer service activities by up to 30% - but only if those agents have the authorization and API connectivity to take action on behalf of the user.

When an agent can write into a CRM, it transitions from a passive observer to an active participant in revenue operations. It can enrich inbound leads, route them based on territory rules, log automated meeting notes, and flag stale opportunities directly in the system of record. However, granting an LLM write access introduces severe engineering challenges. You are no longer just fetching data; you are mutating production databases based on probabilistic model outputs.

The Engineering Trap of Custom Salesforce and HubSpot Connectors

Building AI agents using frameworks like LangChain, LangGraph, or the Vercel AI SDK is relatively straightforward. Connecting those agents to external SaaS APIs is exceptionally difficult.

Giving an LLM access to external data sounds simple during a local prototype. You write a Node.js or Python function that makes an HTTP request to the HubSpot API, wrap it in a tool schema, and bind it to the model. For a one-off script, this works. For a customer-facing B2B SaaS product, direct connectors quickly turn into a permanent engineering tax.

If you build custom integrations, your team is now responsible for the entire OAuth token lifecycle. The initial OAuth handshake is the easy part. Everything that happens afterward - keeping tokens fresh, handling concurrent refreshes safely, detecting revocations, and securing credentials at rest - is where integrations silently fail in production.

Tokens expire mid-sync. Background jobs hit race conditions because two parallel agent threads tried to refresh the same token simultaneously. A customer changes their password, revoking all active sessions, and your application blindly hammers the provider's API with an invalid token for hours. The security stakes are high. According to the 2025 Verizon DBIR, 22% of breaches began with credential abuse. IBM's 2025 Cost of a Data Breach Report puts the average cost of a U.S. breach at $10.22 million.

Instead of managing OAuth states, refresh token concurrency, and credential encryption yourself, standardizing on a unified API layer allows your team to offload token management. You can read more about these architectural patterns in our guide on what is OAuth token management.

Salesforce Object Query Language (SOQL) is a specialized query language used to search Salesforce data, requiring strict adherence to custom field schemas and relationship mappings that LLMs struggle to generate accurately.

Exposing the raw Salesforce API to an LLM is a recipe for hallucinations. Salesforce instances are heavily customized per enterprise customer. Standard objects like Account and Contact are often modified with dozens of custom fields (appended with __c), and organizations frequently rely entirely on Custom Objects.

If you hand an LLM a tool that accepts raw SOQL queries, the model has to guess the exact schema of the customer's specific Salesforce instance.

Consider a scenario where an agent wants to find high-value deals closing this month.

A human engineer would write: SELECT Id, Name, Amount FROM Opportunity WHERE CloseDate = THIS_MONTH AND Amount > 50000

An LLM, lacking strict schema context, might hallucinate: SELECT DealId, DealName, Value FROM Deals WHERE ClosingDate > '2026-01-01'

This query will fail immediately. To solve this, developers often try to inject the entire Salesforce schema into the LLM's context window. This consumes massive amounts of context, drives up token costs, and increases latency.

The correct architectural approach is to use a unified API that abstracts away SOQL entirely. Instead of asking the LLM to write queries, you provide a normalized list_opportunities tool. The agent passes standard JSON parameters (e.g., {"min_amount": 50000, "closing_this_month": true}). The unified execution layer translates that standardized JSON into the specific SOQL query required by that exact customer's Salesforce instance, mapping standard fields to their __c equivalents automatically. You can explore the mechanics of this translation in our guide on how to handle custom fields and custom objects in Salesforce via API.

Handling HubSpot API Rate Limits and 429 Errors

API rate limiting is a defensive mechanism used by SaaS providers to restrict the number of requests a client can make within a specific timeframe, returning HTTP 429 Too Many Requests errors when limits are exceeded.

AI agents are notoriously aggressive API consumers. When an agent uses a tool to process a list of 50 contacts, it often attempts to execute 50 parallel API calls simultaneously.

HubSpot enforces strict burst limits. Depending on the customer's tier, HubSpot might limit applications to 100 requests per 10 seconds. An AI agent running parallel tool calls will exhaust this burst limit in milliseconds. Scopious Digital notes that AI agents can generate bursts of API calls that no human would, making rate limit handling an absolute necessity for production deployments.

When a rate limit is hit, the upstream API returns an HTTP 429 status code.

It is a common misconception that unified APIs absorb and automatically retry these errors for you. In reality, Truto does not retry, throttle, or apply backoff on rate limit errors. When HubSpot returns a 429, Truto passes that error directly back to your application.

However, Truto normalizes the chaotic, vendor-specific rate limit headers into standardized IETF headers:

  • ratelimit-limit: The total request quota.
  • ratelimit-remaining: The remaining requests in the current window.
  • ratelimit-reset: The time when the quota resets.

Your application layer is responsible for reading these headers and implementing exponential backoff.

import time
import requests
 
def execute_agent_tool_with_backoff(url, payload, max_retries=3):
    for attempt in range(max_retries):
        response = requests.post(url, json=payload)
        
        if response.status_code == 429:
            # Read normalized IETF headers provided by Truto
            reset_time = int(response.headers.get('ratelimit-reset', 5))
            print(f"Rate limit hit. Backing off for {reset_time} seconds.")
            time.sleep(reset_time)
            continue
            
        response.raise_for_status()
        return response.json()
        
    raise Exception("Max retries exceeded after 429 errors.")

By relying on standardized headers, your agent framework can use the exact same retry logic for HubSpot, Salesforce, or any other integration.

How Do I Connect an AI Agent to Read and Write Data in Salesforce and HubSpot?

To connect an AI agent to Salesforce and HubSpot safely, you must decouple the agent's reasoning loop from the API execution layer.

Instead of writing raw HTTP requests to vendor endpoints, you define Python or Node.js functions that interact with a unified API. You then bind these functions as tools to your LLM framework. This approach is detailed extensively in our research on architecting AI agents and the SaaS integration bottleneck.

1. Define the Unified Tool Schema

Using LangChain as an example, you define a tool that accepts a standardized input. The LLM does not need to know if the underlying system is Salesforce or HubSpot. It only knows it has a tool to create a contact.

from langchain.tools import tool
import requests
 
@tool
def upsert_crm_contact(tenant_id: str, email: str, first_name: str, last_name: str) -> str:
    """
    Creates or updates a contact in the customer's CRM.
    Use this tool when you need to save a new lead or update an existing person's details.
    """
    # The LLM calls this function. The function calls the unified API.
    url = f"https://api.truto.one/unified/contacts"
    headers = {
        "Authorization": f"Bearer YOUR_TRUTO_API_KEY",
        "x-tenant-id": tenant_id # Identifies which customer's CRM to target
    }
    payload = {
        "email": email,
        "first_name": first_name,
        "last_name": last_name
    }
    
    response = requests.post(url, json=payload, headers=headers)
    if response.status_code == 200:
        return f"Successfully upserted contact. ID: {response.json().get('id')}"
    else:
        return f"Failed to upsert contact: {response.text}"

2. Bind the Tool to the Agent

Once the tool is defined, you bind it to your LLM. The agent will read the docstring and parameter types to understand when and how to invoke the tool.

from langchain_openai import ChatOpenAI
from langchain.agents import initialize_agent, AgentType
 
llm = ChatOpenAI(model="gpt-4o", temperature=0)
tools = [upsert_crm_contact]
 
agent = initialize_agent(
    tools,
    llm,
    agent=AgentType.OPENAI_FUNCTIONS,
    verbose=True
)
 
# The agent decides to use the tool based on the prompt
agent.run("We just had a great call with jane.doe@example.com (Jane Doe). Please save her to the CRM for tenant 'customer_123'.")

3. The Execution Architecture

When the agent decides to act, the execution flows through the unified API, which handles the vendor-specific complexity.

sequenceDiagram
    participant LLM as Agent LLM
    participant App as Your Application
    participant Truto as Truto Unified API
    participant CRM as Upstream CRM (Salesforce/HubSpot)

    LLM->>App: Tool Call (upsert_crm_contact)
    App->>Truto: POST /unified/contacts (Standard JSON)
    
    note over Truto: Retrieves active OAuth token<br>Maps standard JSON to vendor schema
    
    Truto->>CRM: POST /services/data/v58.0/sobjects/Contact (Vendor JSON)
    CRM-->>Truto: 200 OK (Vendor ID)
    
    note over Truto: Normalizes response data
    
    Truto-->>App: Normalized Contact Record
    App-->>LLM: Tool Result (Success)

This architecture ensures that your application logic remains clean. If a customer switches from HubSpot to Salesforce, your agent code does not change. The unified API routes the request to the new provider, mapping the fields appropriately.

Primary Agent Use Cases for Read/Write CRM Access

Once bidirectional connectivity is established, AI agents can take over highly complex, multi-step revenue operations workflows. Based on common integration patterns, here are the primary use cases for read/write CRM agents.

AI-Powered Lead Enrichment and Routing

When an inbound web lead is captured, an agent can check the CRM for an existing account. If none exists, it can use an external data provider tool to enrich the company data. The agent then autonomously creates the Account and Lead records in Salesforce, and generates a Task for the appropriate sales representative based on territory routing rules.

Automated Meeting Logging

Intelligent calendar integrations can parse meeting transcripts and automatically generate summarized notes. The agent uses unified endpoints to log the meeting engagement against the correct Contact and Opportunity in HubSpot, ensuring the CRM is always up to date without manual data entry from the sales team.

Pipeline Hygiene and Stale Deal Alerts

Agents can be scheduled to periodically poll Opportunities, checking their associated pipeline stages and recent engagements. If a high-value deal has not had a logged interaction in 14 days, the agent can automatically alert the assigned user via Slack or Microsoft Teams, prompting them to take action.

Natural Language CRM Querying (RAG)

Sales leaders want to ask conversational questions like, "What enterprise deals are closing this month?" The agent's prompt engine translates this intent into API calls, fetching Opportunities filtered by close date and stage. It then presents the structured data as a conversational summary, effectively replacing complex reporting dashboards with a natural language interface.

Treating Agent Write Access Like Production Infrastructure

If an agent can write into a CRM, treat it like production infrastructure from day one. LLMs are non-deterministic; they will eventually make mistakes, hallucinate parameters, or attempt to execute the wrong tool.

To mitigate these risks, enforce strict security boundaries at the API layer:

  1. Narrow Tool Scopes: Do not give an agent a generic update_record tool that can modify any object in the CRM. Provide specific, narrow tools like update_opportunity_stage to constrain the agent's blast radius.
  2. Idempotency: AI agents frequently retry tool calls if they experience network latency or get confused. Always use idempotency keys when creating records to prevent the agent from accidentally creating duplicate contacts or deals during a retry loop.
  3. Account-Scoped Authentication: Ensure that the agent only has access to the specific OAuth token of the user who invoked it. Never use a master service account to execute agent actions across multiple tenants.
  4. Human-in-the-Loop Approval Gates: For highly consequential actions - like deleting a record or sending an external email - require the agent to pause execution and request human approval via a UI prompt before firing the API call.

Building AI agents is a data problem, not just a prompt engineering problem. By standardizing on a unified execution layer, you remove the integration bottleneck, allowing your engineering team to focus on building intelligent agent workflows rather than maintaining OAuth tokens and parsing SOQL errors.

FAQ

How do I connect an AI agent to read and write data in Salesforce and HubSpot?
You connect AI agents to CRMs by exposing business-level API endpoints (tools) to your LLM framework (like LangChain), routing requests through a unified API layer that handles OAuth, schema mapping, and rate limits.
Can LLMs write SOQL queries for Salesforce?
While LLMs can generate basic SOQL, they consistently fail in production because they lack the context of a customer's specific custom fields and object relationships. It is better to use a unified API to abstract the query generation entirely.
How do AI agents handle HubSpot API rate limits?
AI agents frequently hit HubSpot's 429 Too Many Requests errors due to burst limits. Developers must implement exponential backoff in their tool execution layer using standardized rate limit headers.
What is the best way to prevent AI agents from creating duplicate CRM records?
Always implement idempotency keys in your API requests and restrict your agent to narrow tool scopes to prevent duplicate records during retry loops.

More from our Blog