---
title: How to Connect AI Agents to Read and Write Data in Salesforce and HubSpot
slug: how-to-connect-an-ai-agent-to-read-and-write-data-in-salesforce-and-hubspot
date: 2026-08-24
author: Uday Gajavalli
categories: ["AI & Agents", Guides, Engineering]
excerpt: Architect a unified execution layer that allows your AI agents to securely read and write data across Salesforce and HubSpot APIs while handling OAuth and rate limits.
tldr: "Connecting AI agents to CRMs requires a unified execution layer to handle OAuth, rate limits, and proprietary query languages. Expose narrow, business-level tools so the LLM reasons about intent rather than API boilerplate."
canonical: https://truto.one/blog/how-to-connect-an-ai-agent-to-read-and-write-data-in-salesforce-and-hubspot/
---

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


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 hope prompt engineering compensates for the gap. You must place a unified execution layer between your agent framework 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 proprietary query languages, OAuth token refreshes, pagination, and rate limits, freeing the agent to reason entirely about intent rather than API mechanics.

The pressure to ship autonomous workflows is not merely academic. 88% of B2B organizations are adopting or planning to adopt AI agents, according to Forrester's State of Customer Obsession Survey, 2025. Furthermore, 91% of customer service leaders report executive pressure to implement AI-driven solutions. But giving an LLM write access to an enterprise CRM is a massive architectural risk. If your agent cannot reliably pull a deal from Salesforce, update the pipeline stage, and log a meeting note in HubSpot without hallucinating field names or dropping the OAuth context, your project will not survive production.

The failure rate is just as real as the demand: Gartner predicts that over 40% of agentic AI projects will be canceled by the end of 2027 due to escalating costs, unclear business value, or inadequate risk controls. The uncomfortable truth is that most of those escalating costs are not model spend or prompt tuning. They are the connector tax—the endless engineering hours spent keeping OAuth refreshes, schema drift, and rate-limit handling from breaking your agent in production.

## Why Read-Only AI Agents Aren't Enough for Modern 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.**

If your agent can only summarize a deal, it is essentially a dashboard or a chatbot with extra steps. Read-only assistants are useful for basic summarization and internal knowledge retrieval, but read/write assistants are where the business case gets serious. An agent that can read a deal, negotiate via email, and update the CRM stage autonomously is a scalable revenue engine. The business case for autonomous CRM agents sits squarely on write operations: logging engagements, updating pipeline stages, creating tasks, and enriching accounts.

The economic pull is aggressive. Salesforce reports that 83% of sales teams using AI saw revenue growth in the past year, compared to 66% of teams not using AI. Gartner projects that by 2029, agentic AI will autonomously resolve 80% of common customer service issues without human intervention, leading to a 30% reduction in operational costs.

Meanwhile, native offerings pitch themselves as the shortest path because they operate inside a single platform's data model with inherited governance. That is genuinely useful if your product lives entirely inside one CRM. However, if your B2B SaaS product needs to write into *whichever* CRM the customer happens to use, you cannot pick a side. You need a portable execution layer that speaks both dialects. The most interesting agent workflows are cross-CRM by definition, requiring reliable, bidirectional access. See our deeper breakdown in [How to Connect AI Agents to Read and Write Data in Salesforce and HubSpot](https://truto.one/how-to-connect-ai-agents-to-read-and-write-data-in-salesforce-and-hubspot/) for the wider architectural framing.

## The Integration Bottleneck: Connecting AI Agents to Salesforce and HubSpot

When you ask an LLM to "find all enterprise accounts in the software industry," the model has to translate that natural language intent into a specific API request. Handing an LLM the raw Salesforce REST API and HubSpot CRM API sounds elegant in a demo, but in production, it becomes a maintenance disaster. You are forcing the model to understand the distinct architectural philosophies of two entirely different platforms.

Consider what a single "find all open opportunities for Acme Corp" query requires across both systems:

*   **Salesforce:** Construct a SOQL (Salesforce Object Query Language) query with proper escaping, respect the 100-record default paging limit, follow `nextRecordsUrl` cursors, handle field-level security errors, and map custom fields with `__c` suffixes. The LLM must generate a valid string like: `SELECT Id, Name FROM Account WHERE Industry = 'Software'`.
*   **HubSpot:** Build a complex JSON payload containing `filterGroups` with AND/OR logic sent via a POST request to a search endpoint. It must respect the 100-record hard cap on `/crm/v3/objects/deals/search`, follow `paging.next.after` cursors, and reconcile associations via a separate `/associations` call.

Now multiply that by every entity—contacts, accounts, deals, notes, tasks, engagements—and every write operation. The surface area is huge.

### The Problem with Raw API Tooling

The naive shortcut is to expose one tool per raw endpoint (e.g., exposing the raw LangChain or LangGraph REST tools) and let the LLM stitch calls together. When you do this, you encounter three immediate failure modes:

1.  **Schema Hallucination:** LLMs are trained on public documentation, much of which is outdated. They will inevitably cross-contaminate the syntax. They will try to send SOQL to HubSpot, or they will hallucinate Salesforce's `__c` custom field suffixes onto standard HubSpot properties. They call `crm/v3/objects/contacts/search` when they meant `/deals`.
2.  **Pagination Failures:** Salesforce uses offset pagination or cursor-based links. HubSpot uses an `after` cursor. An autonomous agent trying to aggregate 500 records will frequently drop the pagination state, resulting in incomplete data processing.
3.  **Payload Complexity:** Constructing a nested JSON payload for a HubSpot batch update requires strict typing. LLMs often fail to format the arrays correctly, leading to HTTP 400 Bad Request errors.

Every failure round-trips through more tokens, blowing up latency and cost. The alternative is a **narrow, business-level tool interface** that maps one agent intent to one deterministic call:

```python
# Instead of exposing raw endpoints, expose intent-level tools
tools = [
    "find_contact(email: str) -> Contact",
    "upsert_account(domain: str, name: str, industry: str) -> Account",
    "list_open_deals(account_id: str, min_amount: float) -> list[Deal]",
    "log_engagement(deal_id: str, note: str, type: str) -> Engagement",
]
```

Each tool resolves to a unified data model, and the execution layer translates it into the correct SOQL or HubSpot search payload behind the scenes. The LLM never sees the vendor's warts.

## Handling Authentication: OAuth Token Management for Autonomous Agents

**OAuth token management for AI agents is the process of securely storing, refreshing, and applying tenant-specific access tokens to API requests without requiring synchronous human intervention.**

OAuth is where most in-house integrations bleed out. Traditional SaaS integrations operate synchronously: a user clicks a button, the app makes an API call. If the token is expired, the app refreshes it on the fly or prompts the user. 

AI agents operate asynchronously and unpredictably. A user might trigger a workflow that takes an agent 45 minutes to process a massive batch of leads, cross-referencing them against external enrichment APIs before writing them back to the CRM. Salesforce access tokens expire based on session policy (often 15 minutes to 2 hours). HubSpot access tokens expire after 30 minutes. If the token expires at minute 30, a direct integration fails, and the agent's entire thought process is lost.

An autonomous agent cannot pause and ask a user to re-authenticate at 3 a.m. Your platform needs to handle this in the background:

1.  **Schedule refreshes ahead of expiry:** Waiting until you receive a 401 Unauthorized is too late—you have already burned a tool call and probably confused the agent's reasoning loop. The system must monitor the Time-To-Live (TTL) of every token and refresh it proactively.
2.  **Serialize refreshes per connection:** Concurrent AI workers hitting refresh at the same time will invalidate each other's tokens on providers that rotate refresh tokens on use.
3.  **Distinguish transient failures from revoked grants:** A 401 during a refresh usually means the user disconnected the app in Salesforce Setup. That is a user-facing state change, not a retry candidate.
4.  **Encrypt tokens with per-tenant keys:** A single compromised secret in a multi-tenant agent platform is a catastrophic breach.

When the agent decides to execute a tool, the unified layer intercepts the request, injects the guaranteed-fresh bearer token into the header, and proxies the request. For a deeper look at the trade-offs, see our [B2B SaaS guide to OAuth token management](https://truto.one/what-is-oauth-token-management-the-b2b-saas-guide/).

> [!WARNING]
> **Never store OAuth tokens in your agent framework's memory or vector store.** Frameworks like LangChain and LangGraph were not designed as credential vaults. Keep tokens in a dedicated secrets store, fetch them at call time, and never let them cross into prompt context.

## Managing API Rate Limits and Error Handling

AI agents are incredibly fast. Left unchecked, an agent looping through a list of 1,000 contacts to update their lead scores will instantly trigger upstream rate limits. Salesforce enforces daily API request limits based on org edition and license count, alongside concurrent request limits. HubSpot enforces a strict 10-second rolling window for API calls, plus daily limits by tier.

When an upstream API returns an HTTP 429 Too Many Requests, the worst thing you can do is let the LLM see the raw error and attempt to "reason" its way out of it. The model will likely spam the endpoint repeatedly, resulting in a hard ban from the CRM provider.

### Standardizing Rate Limit Headers

A production-grade unified API layer standardizes how your application reads rate limits. Rather than silently retrying, throttling, or absorbing errors—which can break asynchronous agent architectures—the platform should pass the error straight through to the caller but normalize the wildly inconsistent vendor signals into IETF standardized headers:

*   `ratelimit-limit`: The maximum number of requests permitted in the current window.
*   `ratelimit-remaining`: The number of requests remaining in the current window.
*   `ratelimit-reset`: The time (in seconds) at which the current rate limit window resets.

This design is intentional. Agent workflows have very different tolerance profiles. A background reconciliation job can back off for minutes. An interactive Slack agent responding to a sales rep needs to fail fast and tell the user "try again in 30 seconds." A queue-driven enrichment worker needs to shed load and re-enqueue.

### Implementation Examples: Synchronous vs. Asynchronous Backoff

If your agent is running a synchronous loop, you should implement a circuit breaker that pauses the execution loop entirely using the `ratelimit-reset` header. Do not burn LLM tokens asking the model to "wait and try again."

```python
# Synchronous Python Example
import time
import requests

def execute_crm_tool(tool_name, payload):
    max_retries = 3
    base_delay = 2

    for attempt in range(max_retries):
        response = requests.post(
            f"https://api.unified-layer.com/crm/{tool_name}",
            json=payload,
            headers={"Authorization": "Bearer YOUR_TOKEN"}
        )

        if response.status_code == 429:
            reset_time = response.headers.get('ratelimit-reset')
            sleep_duration = max(0, int(reset_time) - int(time.time())) if reset_time else base_delay ** attempt
                
            print(f"Rate limited. Sleeping for {sleep_duration} seconds.")
            time.sleep(sleep_duration)
            continue
            
        response.raise_for_status()
        return response.json()
        
    raise Exception("Max retries exceeded after rate limit.")
```

If your agent is operating in an asynchronous, queue-driven environment, the pattern should defer work rather than blocking the thread:

```typescript
// Asynchronous TypeScript Example
async function callTool(toolName: string, args: object) {
  const res = await unifiedApi.tools.invoke(toolName, args);

  if (res.status === 429) {
    const resetSeconds = Number(res.headers['ratelimit-reset']) || 30;
    // Push work back to a queue, don't block the agent loop
    await queue.enqueue({ toolName, args, delaySec: resetSeconds });
    return { status: 'deferred', retryAfter: resetSeconds };
  }

  if (res.status >= 500) {
    // Exponential backoff with jitter for transient upstream failures
    return retryWithBackoff(() => unifiedApi.tools.invoke(toolName, args));
  }

  return res.data;
}
```

Pair this with **idempotency keys on writes** so a retried `upsert_contact` never creates duplicates.

## Building a Unified Execution Layer for LLM Function Calling

To safely connect an agent to both Salesforce and HubSpot, you must build or buy a unified execution layer. This layer exposes a normalized data model to the LLM. Instead of teaching the model about Salesforce `Account` objects and HubSpot `Company` objects, you teach it about a single, unified `Company` concept.

### The Architecture of Unified Tool Calling

When you use a unified API, the architecture follows a strict sequence that isolates the LLM from the integration complexity.

```mermaid
sequenceDiagram
    participant LLM as LLM (OpenAI/Anthropic)
    participant Agent as Agent Framework
    participant Unified as Unified API Layer
    participant CRM as Upstream API (Salesforce)

    Agent->>LLM: Prompt with unified tools (e.g., upsert_account)
    LLM->>Agent: Call tool: upsert_account with JSON args
    Agent->>Unified: POST /unified/crm/accounts
    Unified->>Unified: Map normalized fields to upstream schema
    Unified->>Unified: Inject fresh OAuth token
    Unified->>CRM: PATCH /services/data/vXX.X/sobjects/Account
    CRM-->>Unified: 200 OK (Record ID)
    Unified-->>Agent: Normalized Account Object
    Agent-->>LLM: Return tool execution result
```

Instead of exposing full CRUD access to the entire CRM, define narrow, purpose-built tools for your agent. For example, define a tool called `upsert_account`. The LLM only needs to provide the company name and domain. The unified layer handles the mapping configuration that links these unified fields to the provider-specific fields (e.g., mapping `domain` to `Website` in Salesforce or `domain` in HubSpot).

```json
{
  "type": "function",
  "function": {
    "name": "upsert_account",
    "description": "Creates a new account or updates an existing one based on the company domain.",
    "parameters": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "description": "The legal name of the company"
        },
        "domain": {
          "type": "string",
          "description": "The primary website domain of the company (e.g., acme.com)"
        }
      },
      "required": ["name", "domain"]
    }
  }
}
```

Here is what binding those tools looks like in LangChain, agnostic to which CRM the tenant connected:

```python
from langchain_openai import ChatOpenAI
from unified_api_sdk import UnifiedTools

# One call fetches the tool schema for whichever CRM this tenant uses
tools = UnifiedTools.for_tenant(
    tenant_id="acme-corp",
    unified_model="crm",
    allowed_tools=[
        "find_contact",
        "upsert_contact",
        "list_open_deals",
        "log_engagement",
    ],
)

llm = ChatOpenAI(model="gpt-4o").bind_tools(tools)

response = llm.invoke([
    ("system", "You are a sales ops agent. Use tools to update CRM state."),
    ("user", "Log a discovery call with jane@acme.com and move the deal to Stage 2."),
])
```

The exact same agent logic—and the exact same prompt—works seamlessly whether the end-user has connected their Salesforce instance or their HubSpot instance. The cross-CRM translation happens entirely within the unified layer.

### Enforcing Architectural Rules at the Boundary

When exposing these tools, enforce strict rules at the boundary:

*   **Scope tools per user, not per app:** The token used for a call should match the user who authorized it, so audit logs and permission checks work as expected.
*   **Whitelist tools per agent:** A support agent should not have `delete_opportunity` in its toolbox.
*   **Add approval gates on destructive writes:** Bulk deletes, deal-stage changes above a dollar threshold, and account merges deserve a human-in-the-loop check.
*   **Emit structured audit events:** Every tool call should log tenant, user, tool name, arguments hash, and outcome for compliance replay.

For more architectural patterns on this, see our guide on [what is LLM function calling for integrations](https://truto.one/what-is-llm-function-calling-for-integrations-2026-guide/).

## Primary Agent Use Cases in Unified CRM

Once you have established a secure, normalized read/write connection, the workflows that used to require months of connector work become straightforward orchestration problems. Here are the primary use cases driving adoption in B2B SaaS:

### 1. AI-Powered Lead Enrichment & Routing
When an inbound web lead is captured, an agent can check for an existing `Account`. If none exists, it can use an external data provider (like Clearbit or ZoomInfo) to enrich the company data, create the `Account` and `Lead` records via the unified API, and generate a `Task` for the appropriate `User` based on complex territory rules. The agent handles the entire triage process autonomously through one unified tool surface.

### 2. Automated Meeting Logging
Sales reps despise manual data entry. An intelligent calendar integration can parse meeting transcripts, automatically generate summarized `Notes`, and use the unified `Engagements` endpoint to log the meeting against the correct `Contact` and `Opportunity`. This guarantees high-fidelity CRM data without rep intervention. The same tool call works whether the tenant is on Salesforce or HubSpot.

### 3. Pipeline Hygiene & Stale Deal Alerts
Agents can act as autonomous sales managers. An agent can be scheduled to periodically poll `Opportunities` and their associated `Stages` and `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 Teams with a summarized recap and next-step suggestions, and update a custom "At Risk" flag on the CRM record.

### 4. Natural Language CRM Querying (RAG)
Enable sales leaders to ask questions like, "What deals are closing this month over $50K that have not had a meeting in two weeks?" The prompt engine translates this into unified API calls, fetching `Opportunities` filtered by close date and checking related `Engagements`. It then presents the structured data as a conversational summary, effectively replacing complex CRM reporting dashboards with a natural language interface. This pattern is the [easiest way to pull real-time CRM context into an LLM prompt](https://truto.one/easiest-way-to-pull-real-time-crm-context-into-an-llm-prompt/) without relying on stale caches. For a complete walkthrough, see [Connect HubSpot to AI Agents: Sync invoices, orders, and workflows](https://truto.one/connect-hubspot-to-ai-agents-sync-invoices-orders-and-workflows/).

None of these require the agent to know the difference between a Salesforce `Opportunity.StageName` and a HubSpot `deal.dealstage`. The unified model collapses that distinction.

## Where This Approach Stops Being Enough

Radical honesty: a unified execution layer is not a free lunch. There are cases where it will hurt more than help.

*   **Deep custom object graphs:** If your customer has a heavily customized Salesforce org with hundreds of custom objects and complex triggers, the unified model will cover the standard entities and leave you to add passthrough calls for the rest.
*   **Latency-critical single-CRM workflows:** If you only ever integrate with one CRM and every millisecond counts, a hand-tuned direct client may edge out any abstraction layer.
*   **Ultra-specific vendor features:** Salesforce Flow triggers, HubSpot workflow enrollments, and other vendor-native primitives may require raw API access alongside the unified surface.

The practical pattern is hybrid: use the unified layer for 90% of standard CRUD and orchestration, and drop to a passthrough call for the remaining vendor-specific edge cases. That way you avoid the connector tax for everything portable while retaining full control where it matters.

## Strategic Next Steps for Engineering Teams

Connecting an AI agent to read and write data in Salesforce and HubSpot is not a prompt engineering challenge; it is an infrastructure challenge. If you rely on direct API calls, your team will drown in OAuth token lifecycle management, undocumented vendor edge cases, and rate limit bans.

If you are staring down the roadmap of building this yourself, follow this sequence to survive production:

1.  **Define a narrow tool surface:** Identify the smallest set of business-level tools your agent needs. Ten well-scoped tools beat fifty raw endpoints.
2.  **Automate OAuth background refresh:** Wire OAuth token storage and schedule access token refreshes before expiry. Do this before you write a single agent prompt.
3.  **Define your rate-limit contract:** Decide how the agent responds to HTTP 429. Read the standardized IETF rate limit headers and implement a circuit breaker or queue deferral based on workflow tolerance.
4.  **Add idempotency and audit logging:** Attach idempotency keys to every write call so retries do not create duplicates.
5.  **Gate destructive operations:** Require human approval for bulk deletes and high-value deal-stage changes.

Stop building custom CRM connectors for your AI agents. Focus your engineering cycles on improving the agent's core reasoning capabilities, and let a unified execution layer absorb the complexities of SOQL, HubSpot search payloads, and HTTP 429 backoff requirements.

> Building an AI agent that needs to read and write into Salesforce, HubSpot, or 200+ other SaaS platforms? Let's walk through your architecture and show you exactly how Truto's unified execution layer collapses months of connector work into a single tool binding.
>
> [Talk to us](https://cal.com/truto/partner-with-truto)
