Connect Heap to AI Agents: Automate Account and Event Ingestion
Give your AI agent Heap tools.
Connect Heap to AI agents using Truto's SDK. This guide covers bypassing Heap API quirks, binding proxy tools to LLMs, handling rate limits, and orchestrating autonomous analytics workflows.
In this guide
- 01Initialize the LLM
- 02Fetch Heap Tools
- 03Bind Tools to Agent
- 04Implement Rate Limit Backoff
- 05Execute the Agent Loop
The guide
Learn how to connect Heap to AI agents using Truto's /tools endpoint. Automate event tracking, user identity resolution, and account enrichment safely.
You want to connect Heap to an AI agent so your system can autonomously map user identities, inject server-side events, enrich account properties, and process privacy deletions. Here is exactly how to do it using Truto's /tools endpoint and SDK, bypassing the need to build and maintain a custom Heap integration from scratch.
Giving a Large Language Model (LLM) read and write access to your product analytics instance is an engineering headache. You either spend weeks writing custom HTTP clients, handling unique identity schemas, and fighting rate limits, or you use a managed infrastructure layer that handles the boilerplate for you. If your team uses ChatGPT, check out our guide on connecting Heap to ChatGPT, or if you are building on Anthropic's models, read our guide on connecting Heap 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 Heap, bind them natively to an LLM using frameworks like LangChain, LangGraph, CrewAI, or the Vercel AI SDK, and execute complex analytics operations. For a broader look at this design pattern across multiple SaaS platforms, refer to our research on architecting AI agents and the SaaS integration bottleneck.
Why a Unified Tool Layer Matters for Agent Safety
Before writing a line of integration code, decide what layer your agent talks to. Direct API integrations - writing one custom function per raw Heap endpoint - look convenient in a prototype but push provider-specific quirks directly into the LLM's context. The model has to memorize that Heap expects flat key-value pairs for properties, that user IDs and identities have strict collision rules, and that bulk updates return plain text instead of JSON. Every one of those quirks is a hallucination waiting to happen.
A unified tool layer collapses these inconsistencies behind a stable schema. Your agent sees deterministic functions like create_a_heap_event, update_a_heap_identity_by_id, and update_a_heap_account_by_id. This approach yields concrete safety wins for production AI agents:
- Smaller attack surface for hallucination. The LLM only chooses from a defined set of stable function names. It never invents endpoint paths or malformed property arrays.
- Deterministic input validation. Every tool has a strict JSON schema. Invalid arguments (like passing both
identityanduser_idwhen only one is allowed) are rejected before they hit the Heap API. - Framework agnostic execution. Tools formatted as standard JSON schemas can be passed into
.bindTools()in LangChain, or mapped directly to the Vercel AI SDK, without rewriting the underlying HTTP logic.
The Engineering Reality of the Heap API
Giving an AI agent access to external systems sounds simple until you hit the engineering reality of the vendor's API. If you hardcode API requests into your agent, you will spend your sprints writing defensive integration code instead of improving your model's reasoning capabilities. Heap introduces specific challenges that break standard REST assumptions.
The 10-to-1 Identity Window Trap
Heap's identity resolution is strict. When an agent attempts to map an anonymous SDK user_id to a known identity (like an email address) using the update_a_heap_identity_by_id tool, it must navigate tight rate and relationship limits. Heap allows only one identity per user_id, and critically, at most 10 user_ids can be mapped to a single identity within a rolling one-month window. If an AI agent running a high-volume data enrichment loop blindly fires identity updates for every interaction, Heap will silently ignore the extra calls after the tenth mapping. Your agent needs a tool schema that clearly defines these parameters so it can reason about when to map identities versus when to simply attach properties to an existing record.
Non-JSON Success Acknowledgements
Standard LLMs and modern agent frameworks are trained to expect flat, intuitive JSON objects. When an agent successfully calls an API, the framework attempts to parse the response as JSON to feed it back into the context window. However, Heap's update_a_heap_account_by_id endpoint returns a plain-text OK success acknowledgment with no structured body. If you build a direct integration, your JSON parser will throw a syntax error, causing the agent to think the tool call failed. It will then retry the identical payload, creating a loop. A managed tool abstraction normalizes these responses into empty JSON objects or standard success payloads, preventing the LLM from entering a panic state.
Asynchronous State Management for Privacy Deletions
Executing GDPR or CCPA compliance deletions in Heap is not a synchronous HTTP request. When you submit users for deletion, the API responds with a deletion_request_id and a status. The agent cannot simply fire and forget; it must pause, retain the deletion_request_id in its state, and periodically poll the get_single_heap_user_deletion_by_id endpoint. Teaching an LLM to reliably manage async polling across multiple conversation turns is notoriously difficult. Exposing both the submission tool and the polling tool with explicit instructions in their descriptions is the only way to achieve reliable autonomous privacy compliance.
Core Heap AI Agent Tools
Truto provides a dynamic /tools endpoint that serves pre-configured proxy APIs formatted specifically for LLM function calling. Below are the highest-leverage tools available for Heap automation.
create_a_heap_event
This tool allows the agent to send custom server-side events to Heap. This is critical for tracking backend transactions, subscription changes, or automated AI operations that cannot be captured by client-side SDKs.
Usage Note: The agent must supply the app_id and event name. It must supply either identity (known user) or user_id (anonymous user), but never both. The tool returns an empty JSON object on success.
"A user with the identity 'sarah@example.com' just upgraded to the Enterprise tier via Stripe. Log a server-side event in Heap called 'Subscription Upgraded' and include the property 'MRR_Increase' set to 500."
update_a_heap_identity_by_id
This tool maps an anonymous session user_id to a known identity, migrating all historical session events to the permanent user profile.
Usage Note: The agent must be aware of the 10-identities-per-month limit. It requires app_id, user_id, and identity.
"We just collected an email signup from an anonymous session. Map the anonymous user_id '8374928' to the identity 'j.doe@startup.io' in Heap so we retain their past pageviews."
update_a_heap_user_by_id
This tool attaches custom key-value properties to an identified Heap user. If the identity does not exist, Heap automatically creates it as a new user.
Usage Note: Existing properties with the same name will be overwritten. It requires app_id and identity.
"Our Clearbit enrichment agent just found out that 'alex@acmecorp.com' has the job title 'VP of Engineering'. Update this user in Heap and attach the custom property 'Job_Title'."
update_a_heap_account_by_id
This tool manages B2B account properties, allowing the agent to attach or update custom fields for one or more accounts simultaneously.
Usage Note: The agent can use account_id and properties for a single update, or an accounts array for bulk updates. Truto normalizes the plain-text 'OK' response into a structured format.
"The account 'Acme Corp' just reached 50 active seats. Update their account profile in Heap to set 'Seat_Count' to 50 and 'Lifecycle_Stage' to 'Scaled'."
create_a_heap_user_deletion
This tool initiates an asynchronous data deletion request for compliance (GDPR/CCPA). It accepts up to 10,000 users per request.
Usage Note: The agent must provide an array of users, each containing a user_id or identity. It returns a deletion_request_id which the agent must save for polling.
"We received a GDPR Right to be Forgotten request for 'mark@example.com'. Submit a deletion request to Heap for this identity and let me know the deletion request ID."
get_single_heap_user_deletion_by_id
This tool polls the status of a previously submitted asynchronous deletion request.
Usage Note: The agent requires the id (the deletion_request_id). It returns the current status (e.g., pending, completed).
"Check the status of the Heap user deletion request with ID 'del_req_99834'. If it is not completed, we will check again tomorrow."
To view the complete inventory of available Heap proxy tools and their exact JSON schemas, visit the Heap integration page.
Workflows in Action
When you bind these tools to a reasoning engine, the agent can autonomously execute multi-step revenue operations and compliance workflows. Here is what that looks like in practice.
Scenario 1: Autonomous B2B Account Enrichment
When a new company signs up, the agent detects the event, enriches the account data via a third-party tool, and updates the analytics platform.
"A new user 'cto@cybernetics.io' just signed up. Log this as a 'User Signup' event. Then, update their Heap account record with the properties: 'Industry': 'Cybersecurity', 'Employee_Count': '500-1000'."
- The agent calls
create_a_heap_eventpassingidentity: "cto@cybernetics.io"andevent: "User Signup". - The agent interprets the domain to identify the account, then calls
update_a_heap_account_by_idpassingaccount_id: "cybernetics.io"with the nestedpropertiesfor industry and employee count. - The agent returns a confirmation to the user that the event was logged and the B2B account was enriched.
Scenario 2: GDPR Deletion Pipeline
Handling privacy requests requires exact sequencing and state tracking.
"Process a CCPA data deletion for 'david@privacy.org'. Initiate the deletion in Heap and tell me the job ID so we can track it."
- The agent calls
create_a_heap_user_deletionpassingusers: [{"identity": "david@privacy.org"}]. - Heap processes the request asynchronously. The tool returns the response payload containing the
deletion_request_id. - The agent reads the response and informs the user: "Deletion initiated. The tracking ID is
req_8823. You can ask me to check on this ID later."
Building Multi-Step Workflows
To build these workflows in code, you must fetch the tool definitions from Truto and bind them to your LLM. Standard frameworks like LangChain make this straightforward via .bindTools().
However, you must handle network realities. Truto does not retry, throttle, or apply backoff on rate limit errors. When the upstream Heap API returns an HTTP 429 Too Many Requests, Truto passes that error directly to the caller.
What Truto does do is normalize the upstream rate limit information into standardized HTTP headers per the IETF specification:
ratelimit-limit: The maximum number of requests allowed in the current window.ratelimit-remaining: The number of requests remaining.ratelimit-reset: The time at which the rate limit window resets.
The caller (your agent's tool execution loop) is completely responsible for reading these headers, pausing execution, and retrying. Failing to handle 429s will cause your agent to hallucinate fake success states or crash entirely.
The Architecture of a Resilient Tool Loop
Here is how data flows through a rate-limit-aware agent loop:
graph TD
A["User Prompt<br>(Track Server Event)"] --> B["Agent Core<br>(LLM Reasoning)"]
B --> C["Tool Call Execution<br>(create_a_heap_event)"]
C --> D{"HTTP Status?"}
D -->|"200 OK"| E["Return Success<br>to Agent Context"]
D -->|"429 Rate Limit"| F["Extract Header<br>(ratelimit-reset)"]
F --> G["Sleep / Backoff<br>(Client-Side)"]
G --> CImplementation with TypeScript and LangChain
Below is a production-grade example using TrutoToolManager from the truto-langchainjs-toolset SDK. This code initializes the agent, binds the Heap tools, and wraps the execution loop in a custom handler that respects the IETF rate limit headers passed through by Truto.
import { ChatOpenAI } from "@langchain/openai";
import { HumanMessage } from "@langchain/core/messages";
import { TrutoToolManager } from "truto-langchainjs-toolset";
// 1. Initialize the LLM
const llm = new ChatOpenAI({
modelName: "gpt-4o",
temperature: 0,
});
// 2. Fetch Heap tools via Truto for a specific integrated account
const heapTools = await TrutoToolManager.from_integrated_account(
"<TRUTO_INTEGRATED_ACCOUNT_ID>",
"<TRUTO_API_KEY>"
);
// 3. Bind tools to the LLM
const llmWithTools = llm.bindTools(heapTools);
// 4. Rate-limit aware tool execution function
async function executeToolWithBackoff(toolCall: any, tools: any[], maxRetries = 3) {
const tool = tools.find((t) => t.name === toolCall.name);
if (!tool) throw new Error(`Tool ${toolCall.name} not found`);
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
// Execute the tool (makes HTTP request via Truto)
const result = await tool.invoke(toolCall.args);
return result;
} catch (error: any) {
// Check if Truto passed through an upstream 429 Rate Limit
if (error.response && error.response.status === 429) {
console.warn(`[Rate Limit Hit] Attempt ${attempt} of ${maxRetries}`);
// Read the IETF standardized headers provided by Truto
const resetTimeHeader = error.response.headers['ratelimit-reset'];
if (resetTimeHeader && attempt < maxRetries) {
const resetDate = new Date(resetTimeHeader).getTime();
const now = Date.now();
// Calculate backoff, default to 5 seconds if parsing fails
const delayMs = Math.max((resetDate - now), 5000);
console.log(`Sleeping for ${delayMs}ms before retrying...`);
await new Promise(resolve => setTimeout(resolve, delayMs));
continue; // Retry the loop
}
}
// Rethrow if not a 429 or if we exhausted retries
throw error;
}
}
}
// 5. Run the Agent Loop
async function runHeapAgent(prompt: string) {
const messages = [new HumanMessage(prompt)];
// First LLM pass: Model decides which tool to call
const response = await llmWithTools.invoke(messages);
messages.push(response);
// If the model opted to call a tool
if (response.tool_calls && response.tool_calls.length > 0) {
for (const toolCall of response.tool_calls) {
console.log(`Executing: ${toolCall.name}`);
// Execute safely with our backoff wrapper
const toolResult = await executeToolWithBackoff(toolCall, heapTools);
// Pass the result back to the LLM context
messages.push({
role: "tool",
tool_call_id: toolCall.id,
name: toolCall.name,
content: JSON.stringify(toolResult),
});
}
// Final LLM pass: Model summarizes the result
const finalResponse = await llmWithTools.invoke(messages);
console.log("Agent:", finalResponse.content);
} else {
console.log("Agent:", response.content);
}
}
// Execute the workflow
runHeapAgent("Log a server-side event 'API Deployed' for the identity 'dev@example.com'.");This architecture guarantees that your agent will not crash when Heap enforces its rate limits, nor will it hallucinate a successful API call. By relying on Truto's standardized headers, you avoid writing custom header-parsing logic for every SaaS tool you integrate.
Moving from Script to System
Building an AI agent that talks to Heap is not about wrapping a single fetch request in a tool decorator. It is about state management, rate limit handling, and API schema normalization. When you hand an LLM direct access to a raw API, you inherit the provider's technical debt. By using Truto's /tools endpoint, you collapse the engineering complexity of identity maps, plain-text responses, and pagination into a uniform JSON schema that language models can actually understand.
Stop writing defensive integration code and start focusing on your model's reasoning capabilities.
FAQ
- How does Truto handle Heap API rate limits?
- Truto passes upstream 429 rate limit errors directly to the caller and normalizes the rate limit data into standard IETF HTTP headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset). Truto does not automatically retry or absorb these errors, so your agent's execution loop must handle the backoff.
- Can AI agents process async user deletions in Heap?
- Yes. Agents can initiate the deletion using the create_a_heap_user_deletion tool, which returns a deletion_request_id. The agent must retain this ID in its state and poll the get_single_heap_user_deletion_by_id tool to verify completion.
- How does the identity resolution limit work in Heap?
- Heap restricts mapping an anonymous user_id to a known identity to 1 identity per user_id, and at most 10 user_ids per identity in a rolling one-month window. Truto exposes this via the update_a_heap_identity_by_id tool, but the agent must logic around these constraints.
- Why use Truto instead of raw Heap API calls for LangChain?
- Truto normalizes API inconsistencies, such as Heap returning plain-text 'OK' success messages instead of structured JSON, which often breaks LLM tool parsing. It provides deterministic, schema-validated tools that reduce hallucination risk.