Custom tools
Learn how to create custom tools to extend your agent’s capabilities beyond message handling.
Letta’s stateful AI agents can enrich existing Zapier workflows. This guide demonstrates how to create a routing system for customer support tickets by integrating Zapier automation with a Letta agent. The agent remembers customer history, learns routing patterns, and provides intelligent recommendations.
You’ll create the following customer support workflow, and in doing so, learn to add Letta agents to Zapier automations:
graph LR
A["Google Sheets
(New ticket)"] --> B["Letta agent
(Intelligence layer)"] --> C["Slack
(Notification)"]
The Letta agent sits between your trigger and action, analyzing each ticket with full context from previous interactions. This approach adds intelligence to your workflow without replacing your existing tools.
To follow along, you need:
Create a Letta account
If you don’t have one, sign up for a free account at letta.com.
Navigate to API keys
Once logged in, click on API keys in the sidebar.

Create and copy your key
Click + Create API key, give it a descriptive name (such as Zapier Integration), and click Confirm. Copy the key and save it somewhere safe.
Once you have your API key, create a .env file in your project directory:
LETTA_API_KEY=your_letta_api_key_hereIf you don’t have an account, sign up at zapier.com. The free tier works for this tutorial.
Create a new Google Sheet, called Support Tickets, with the following columns:
Ticket ID (Column A)Customer Name (Column B)Customer Email (Column C)Subject (Column D)Description (Column E)Priority (Column F)Make sure you have access to a Slack workspace where you can receive notifications (you’ll connect the workspace to Zapier in Step 3).
First, configure a Letta agent with memory blocks for customer history and routing knowledge.
Create a requirements.txt file that contains the following dependencies:
letta-clientpython-dotenvRun the following code to install the dependencies:
pip install -r requirements.txtCreate a package.json file with the following contents:
{ "name": "letta-zapier-integration", "version": "1.0.0", "description": "TypeScript code for integrating Letta agents with Zapier workflows", "type": "module", "scripts": { "create-agent": "tsx create-agent.ts", "test-ticket": "tsx test-ticket.ts" }, "dependencies": { "@letta-ai/letta-client": "latest", "dotenv": "^16.3.1" }, "devDependencies": { "@types/node": "^20.10.0", "tsx": "^4.7.0", "typescript": "^5.3.0" }}Create a tsconfig.json file with the following contents:
{ "compilerOptions": { "target": "ES2020", "module": "ESNext", "moduleResolution": "node", "esModuleInterop": true, "skipLibCheck": true, "strict": true, "outDir": "./dist", "rootDir": "." }, "include": [ "*.ts" ], "exclude": [ "node_modules", "dist" ]}Install the dependencies:
npm installCreate a script to initialize your Letta agent with three memory blocks:
persona block to define the agent’s role and behaviorrouting_knowledge block to track ticket-routing patternscustomer_history block to maintain the memory of customer interactionsCreate a file named create-agent.py and add the following code to it:
"""Create a Letta agent for intelligent support ticket routing.
This script creates a Letta agent with memory blocks designed to:- Remember customer history across all interactions- Learn routing patterns that lead to faster resolutions- Provide context-aware ticket analysis and routing recommendations
Usage: python create-agent.py
Requirements: - LETTA_API_KEY environment variable set - letta-client package installed"""
import osfrom letta_client import Lettafrom dotenv import load_dotenv
# Load environment variablesload_dotenv()
def create_support_agent(): """Create and configure a support ticket routing agent."""
# Initialize the Letta client api_key = os.getenv("LETTA_API_KEY") if not api_key: raise ValueError("LETTA_API_KEY environment variable not set. Please add it to your .env file.")
client = Letta(api_key=api_key) print("Connected to Letta Cloud")
# Create the agent with memory blocks agent = client.agents.create( name="Support Ticket Router", description="Intelligent support ticket routing assistant with customer memory and learning capabilities", memory_blocks=[ { "label": "persona", "value": """I am an intelligent support ticket routing assistant. My role is to:- Analyze incoming support tickets with full context- Remember customer history across all interactions- Learn which routing decisions lead to fastest resolutions- Provide detailed routing recommendations with reasoning- Continuously improve my routing accuracy over time
I always provide structured responses with routing recommendations, priority levels, and context.""" }, { "label": "routing_knowledge", "value": """I track patterns about ticket routing and resolutions:- Which teams handle which types of issues most effectively- Average resolution times for different issue categories- Patterns in urgent vs routine tickets- Success rates of different routing decisions
I learn from each ticket to improve future routing decisions.""" }, { "label": "customer_history", "value": """I maintain memory of customer interactions:- Previous tickets and their resolutions- Communication preferences (technical level, urgency patterns)- Account-specific issues and patterns- Customer satisfaction indicators
I use this history to provide personalized, context-aware routing.""" } ] )
print(f"Agent created: {agent.id}") print(f"\nAdd this to your .env file:") print(f"LETTA_AGENT_ID={agent.id}")
return agent
if __name__ == "__main__": try: agent = create_support_agent() except Exception as e: print(f"Failed: {e}") raiseCreate a file named create-agent.ts and add the following code to it:
/** * Create a Letta agent for intelligent support ticket routing. * * This script creates a Letta agent with memory blocks designed to: * - Remember customer history across all interactions * - Learn routing patterns that lead to faster resolutions * - Provide context-aware ticket analysis and routing recommendations * * Usage: * npx tsx create-agent.ts * * Requirements: * - LETTA_API_KEY environment variable set * - @letta-ai/letta-client package installed */
import Letta from '@letta-ai/letta-client';import * as dotenv from 'dotenv';
// Load environment variablesdotenv.config();
async function createSupportAgent() { /** * Create and configure a support ticket routing agent. */
// Initialize the Letta client const apiKey = process.env.LETTA_API_KEY; if (!apiKey) { throw new Error("LETTA_API_KEY environment variable not set. Please add it to your .env file."); }
const client = new Letta({ apiKey: apiKey }); console.log("Connected to Letta Cloud");
// Create the agent with memory blocks const agent = await client.agents.create({ name: "Support Ticket Router", description: "Intelligent support ticket routing assistant with customer memory and learning capabilities", memory_blocks: [ { label: "persona", value: `I am an intelligent support ticket routing assistant. My role is to:- Analyze incoming support tickets with full context- Remember customer history across all interactions- Learn which routing decisions lead to fastest resolutions- Provide detailed routing recommendations with reasoning- Continuously improve my routing accuracy over time
I always provide structured responses with routing recommendations, priority levels, and context.` }, { label: "routing_knowledge", value: `I track patterns about ticket routing and resolutions:- Which teams handle which types of issues most effectively- Average resolution times for different issue categories- Patterns in urgent vs routine tickets- Success rates of different routing decisions
I learn from each ticket to improve future routing decisions.` }, { label: "customer_history", value: `I maintain memory of customer interactions:- Previous tickets and their resolutions- Communication preferences (technical level, urgency patterns)- Account-specific issues and patterns- Customer satisfaction indicators
I use this history to provide personalized, context-aware routing.` } ] });
console.log(`Agent created: ${agent.id}`); console.log(`\nAdd this to your .env file:`); console.log(`LETTA_AGENT_ID=${agent.id}`);
return agent;}
// Run the scriptcreateSupportAgent().catch((error) => { console.error(`Failed: ${error.message}`); process.exit(1);});python create-agent.pynpx tsx create-agent.tsYou should see the following output:
Connected to Letta CloudAgent created: agent-abc123def456
Add this to your .env file:LETTA_AGENT_ID=agent-abc123def456Copy your agent ID from the output above and add it to your .env file:
LETTA_API_KEY=your_letta_api_key_hereLETTA_AGENT_ID=agent-abc123def456Before connecting to Zapier, test that your agent analyzes tickets correctly.
This script sends sample support tickets to your agent and displays the routing recommendations.
Create a file named test-ticket.py and add the following code to it:
"""Test script for sending support tickets to the Letta agent.
This script simulates what Zapier does: it sends a support ticketto the Letta agent and receives an intelligent routing recommendation.
Usage: python test-ticket.py
Requirements: - LETTA_API_KEY environment variable set - LETTA_AGENT_ID environment variable set - letta-client package installed"""
import osimport jsonfrom letta_client import Lettafrom dotenv import load_dotenv
# Load environment variablesload_dotenv()
# Sample test ticketsSAMPLE_TICKETS = [ { "customer_name": "John Doe", "subject": "Cannot log in to dashboard", "description": "I'm getting a 500 error when trying to log in. This is the third time this month.", "priority": "High" }, { "customer_name": "Sarah Smith", "subject": "Question about billing", "description": "I was charged twice for my subscription this month. Can someone look into this?", "priority": "Medium" }, { "customer_name": "Mike Johnson", "subject": "Feature request", "description": "Would love to see dark mode added to the app. Many users have been asking for this.", "priority": "Low" }]
def format_ticket_message(ticket): """Format a ticket into a message for the Letta agent.""" return f"""New support ticket received:
Customer: {ticket['customer_name']} ({ticket['customer_email']})Subject: {ticket['subject']}Description: {ticket['description']}Priority: {ticket['priority']}
Please analyze this ticket and provide:1. Recommended team to route to2. Adjusted priority level (if needed)3. Your reasoning based on customer history and patterns4. A suggested response message5. Estimated resolution time"""
def send_ticket_to_agent(client, agent_id, ticket): """Send a ticket to the Letta agent and get routing recommendation."""
# Send message to agent message_content = format_ticket_message(ticket)
response = client.agents.messages.create( agent_id=agent_id, messages=[ { "role": "user", "content": message_content } ] )
# Extract and display the agent's response for message in response.messages: if message.message_type == 'assistant_message': print(message.content) print()
return response
def main(): """Main test function."""
# Get credentials from environment api_key = os.getenv("LETTA_API_KEY") agent_id = os.getenv("LETTA_AGENT_ID")
if not api_key: raise ValueError("LETTA_API_KEY not set. Add it to your .env file.")
if not agent_id: raise ValueError("LETTA_AGENT_ID not set. Run create-agent.py first and add the ID to your .env file.")
# Initialize client client = Letta(api_key=api_key) print("Connected to Letta Cloud") print(f"Using agent: {agent_id}\n")
# Test with sample tickets for i, ticket in enumerate(SAMPLE_TICKETS, 1): print(f"Processing ticket {i}/{len(SAMPLE_TICKETS)}: {ticket['subject']}") try: send_ticket_to_agent(client, agent_id, ticket) except Exception as e: print(f"Failed: {e}") continue
if __name__ == "__main__": try: main() except Exception as e: print(f"Error: {e}") raiseCreate a file named test-ticket.ts and add the following code to it:
/** * Test script for sending support tickets to the Letta agent. * * This script simulates what Zapier does: it sends a support ticket * to the Letta agent and receives an intelligent routing recommendation. * * Usage: * npx tsx test-ticket.ts * * Requirements: * - LETTA_API_KEY environment variable set * - LETTA_AGENT_ID environment variable set * - @letta-ai/letta-client package installed */
import Letta from '@letta-ai/letta-client';import * as dotenv from 'dotenv';
// Load environment variablesdotenv.config();
interface Ticket { customer_name: string; customer_email: string; subject: string; description: string; priority: string;}
// Sample test ticketsconst SAMPLE_TICKETS: Ticket[] = [ { customer_name: "John Doe", subject: "Cannot log in to dashboard", description: "I'm getting a 500 error when trying to log in. This is the third time this month.", priority: "High" }, { customer_name: "Sarah Smith", subject: "Question about billing", description: "I was charged twice for my subscription this month. Can someone look into this?", priority: "Medium" }, { customer_name: "Mike Johnson", subject: "Feature request", description: "Would love to see dark mode added to the app. Many users have been asking for this.", priority: "Low" }];
function formatTicketMessage(ticket: Ticket): string { /** * Format a ticket into a message for the Letta agent. */ return `New support ticket received:
Customer: ${ticket.customer_name} (${ticket.customer_email})Subject: ${ticket.subject}Description: ${ticket.description}Priority: ${ticket.priority}
Please analyze this ticket and provide:1. Recommended team to route to2. Adjusted priority level (if needed)3. Your reasoning based on customer history and patterns4. A suggested response message5. Estimated resolution time`;}
async function sendTicketToAgent(client: Letta, agentId: string, ticket: Ticket) { /** * Send a ticket to the Letta agent and get routing recommendation. */
// Send message to agent const messageContent = formatTicketMessage(ticket);
const response = await client.agents.messages.create(agentId, { messages: [ { role: "user", content: messageContent } ] });
// Extract and display the agent's response for (const message of response.messages) { if (message.message_type === 'assistant_message') { console.log((message as any).content); console.log(); } }
return response;}
async function main() { /** * Main test function. */
// Get credentials from environment const apiKey = process.env.LETTA_API_KEY; const agentId = process.env.LETTA_AGENT_ID;
if (!apiKey) { throw new Error("LETTA_API_KEY not set. Add it to your .env file."); }
if (!agentId) { throw new Error("LETTA_AGENT_ID not set. Run create-agent.ts first and add the ID to your .env file."); }
// Initialize client const client = new Letta({ apiKey: apiKey }); console.log("Connected to Letta Cloud"); console.log(`Using agent: ${agentId}\n`);
// Test with sample tickets for (let i = 0; i < SAMPLE_TICKETS.length; i++) { const ticket = SAMPLE_TICKETS[i]; console.log(`Processing ticket ${i + 1}/${SAMPLE_TICKETS.length}: ${ticket.subject}`);
try { await sendTicketToAgent(client, agentId, ticket); } catch (error: any) { console.error(`Failed: ${error.message}`); continue; } }}
// Run the scriptmain().catch((error) => { console.error(`Error: ${error.message}`); process.exit(1);});python test-ticket.pynpx tsx test-ticket.tsYou should see intelligent routing recommendations for each ticket:
Connected to Letta CloudUsing agent: agent-abc123def456
Processing ticket 1/3: Cannot log in to dashboardBased on the ticket analysis:
Recommended Team: Engineering - BackendPriority Level: HighReasoning: Customer John Doe has reported a 500 error when attempting to log in.This is the third occurrence this month, indicating a recurring technical issuethat requires immediate attention from the backend engineering team. The 500error suggests a server-side problem that needs investigation.
Suggested Response: "Hi John, I see you're experiencing login issues with a 500error. This is the third time this month, and I apologize for the inconvenience.Our backend team is investigating the recurring issue and will prioritize a fix.I'll keep you updated on our progress."
Estimated Resolution Time: 2-4 hours
Processing ticket 2/3: Question about billing...If you see context-aware responses, your agent is working correctly.
You can also view your agent in Letta’s Agent Development Environment (ADE), a visual interface for managing and inspecting agents.
Go to https://app.letta.com and sign in with your Letta account
In the left navigation bar, click Agents. Find your Support Ticket Router agent.

Click Open in ADE.

In the ADE, you can inspect your agent’s configuration, including its:
If you ran the test script, you can see the conversation history and responses in the chat interface:

The ADE provides full visibility into your agent’s configuration and state. When your Zapier workflow runs, you can return to the ADE to see how the agent’s memory evolves as it processes real support tickets.
Learn more about the Agent Development Environment →Now we’ll connect your Letta agent to Zapier to create the automated workflow.
Create a new Zap
In Zapier, click + Create and select Zaps.

Set up the trigger

Configure the trigger

Test the trigger

Now you’ll add the next step to your Zap. This step sends the ticket data to your Letta agent for analysis.
Add a Webhooks action
Configure the request method and URL
https://api.letta.com/v1/agents/YOUR_AGENT_ID_HERE/messagesReplace YOUR_AGENT_ID_HERE with the agent ID from Step 1.
Configure Data Pass-Through
Set Data Pass-Through to False.
This setting ensures the response structure is preserved correctly for the next step.
Configure the request body
In the Data field, paste the following JSON structure:
{ "messages": [ { "role": "user", "content": "New support ticket received:\n\nCustomer: {{Customer Name}} ({{Customer Email}})\nSubject: {{Subject}}\nDescription: {{Description}}\nPriority: {{Priority}}\n\nPlease analyze this ticket and provide:\n1. Recommended team to route to\n2. Adjusted priority level (if needed)\n3. Your reasoning based on customer history and patterns\n4. A suggested response message\n5. Estimated resolution time" } ]}
Add headers
In the Headers section, add an Authorization and a Content-Type header with the following values:
| Header | Value |
|---|---|
| Authorization | Bearer YOUR_LETTA_API_KEY |
| Content-Type | application/json |
Replace YOUR_LETTA_API_KEY with your actual Letta API key.
Test the Webhook
messages array.You can also verify the test worked by checking your agent in the ADE at https://app.letta.com. You should see the test ticket in the conversation history.

Next, create the step that sends a notification to Slack.
Add a Slack action
Configure the Slack message
#support).*New Support Ticket*
*Customer:* {{Customer Name}} ({{Customer Email}})*Subject:* {{Subject}}*Description:* {{Description}}*Priority:* {{Priority}}
---
*Letta AI Recommendation:*
{{Webhooks by Zapier: Messages 0 Content}}
---
View in Google SheetsCustomer Name, Email, and Subject): First, click on the warning or on the field placeholder in the message text to open the dialog. Then, click the Previous Steps tab, expand the 1. New Spreadsheet Row in Google… option, and select the appropriate field.
Test the Slack action

Name your Zap
Click the title at the top and rename it something descriptive, like Intelligent Support Ticket Routing with Letta.
Turn the Zap on
Your Zapier workflow is now live and will process new support tickets automatically.
Add an example ticket to your Google Sheet:
| Ticket ID | Customer Name | Customer Email | Subject | Description | Priority | Timestamp |
|---|---|---|---|---|---|---|
| 1 | James Doe | [email protected] | Cannot access account | Getting an error when logging in | High | 2025-01-15 10:30 AM |
Wait one to two minutes (Zapier polls every 1-15 minutes depending on your plan). You should receive a Slack notification with the following information:
Try adding another ticket from the same customer. The agent will remember the first interaction and provide context-aware routing based on the customer’s history.

Now that you’ve integrated a Letta agent into your Zapier workflow, you can apply this same pattern to other use cases, such as lead qualification, content moderation, or expense approval. Each workflow follows the same structure:
Explore these guides to see how you can extend what you’ve built:
Custom tools
Learn how to create custom tools to extend your agent’s capabilities beyond message handling.
Memory management
Explore how to customize memory blocks for different workflow requirements.