---
title: "Connect Torii to AI Agents: Automate SaaS Lifecycles and App Data"
slug: connect-torii-to-ai-agents-automate-saas-lifecycles-and-app-data
date: 2026-06-09
author: Uday Gajavalli
categories: ["AI & Agents"]
excerpt: "A technical guide to connecting Torii to AI agents using Truto's /tools endpoint. Learn how to automate IT lifecycles, shadow IT discovery, and contract management."
tldr: "Connect Torii to AI agents to automate IT workflows like employee offboarding, shadow IT audits, and SaaS contract reconciliation. This guide details Torii API quirks, rate limit handling, and multi-step agent architectures."
canonical: https://truto.one/blog/connect-torii-to-ai-agents-automate-saas-lifecycles-and-app-data/
---

# Connect Torii to AI Agents: Automate SaaS Lifecycles and App Data


You want to connect Torii to an AI agent so your system can automatically read user directories, execute SaaS offboarding, audit shadow IT, and reconcile contract data. Here is exactly how to do it using Truto's `/tools` endpoint and SDK, bypassing the need to build and maintain a custom connector from scratch.

IT teams are drowning in SaaS sprawl. A March 2026 industry benchmark report indicates that the average mid-market enterprise manages over 300 unique SaaS applications, with identities constantly shifting due to onboarding, role changes, and departures. The industry is rapidly shifting toward agentic IT automation - autonomous systems that work alongside sysadmins to execute multi-step governance workflows. If your team uses ChatGPT, check out our [guide to connecting Torii to ChatGPT](https://truto.one/connect-torii-to-chatgpt-manage-saas-users-apps-and-contracts/), or if you are building exclusively on Anthropic's models, read our [guide to connecting Torii to Claude](https://truto.one/connect-torii-to-claude-audit-saas-usage-contracts-and-workflows/). For developers building custom multi-agent workflows, you need a programmatic way to fetch these tools and bind them to your agent framework.

Giving a Large Language Model (LLM) read and write access to your Torii instance is an engineering challenge. You either spend months building, hosting, and maintaining a custom connector that handles complex pagination and rate limits, or you use a managed infrastructure layer to overcome the [SaaS integration bottleneck](https://truto.one/architecting-ai-agents-langgraph-langchain-and-the-saas-integration-bottleneck/).

This guide breaks down exactly how to fetch AI-ready tools for Torii, bind them natively to an LLM using frameworks like LangChain or Vercel AI SDK, and execute complex IT governance workflows autonomously.

## The Engineering Reality of Torii's API

Building AI agents is trivial. Connecting them to external SaaS APIs safely is a completely different domain. Giving an LLM access to external data sounds simple in a notebook 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 under the weight of real-world API constraints.

Torii's API introduces several specific integration challenges that break standard CRUD assumptions and trip up naive LLM implementations.

### The Junction Object Complexity

Torii maps an extremely complex graph of entities: Users, Applications, and Contracts. Unlike a flat CRM structure, Torii relies heavily on junction objects. If an agent wants to know what apps a user has, it cannot just inspect the user record. It must query `user-applications`, a distinct junction object connecting `id_user` and `id_app`. 

When you ask an LLM to "remove a user from Slack", it often hallucinates an update to the user record itself. To execute this correctly, the agent must first list the user's applications, locate the specific `id` for the Slack association, and then update the `isUserRemovedFromApp` flag on that specific junction object. Providing poorly defined tools will result in the LLM mutating the wrong data.

### Variable Rate Limits and 429 Handling

Torii enforces strict, endpoint-specific rate limits. For example, creating or updating contracts is capped at 800 requests per minute, while updating apps drops to 200 requests per minute. 

If your AI agent goes into a loop attempting to reconcile a massive list of discovered apps against active contracts, it will quickly hit a rate limit and Torii will return an `HTTP 429 Too Many Requests` error. 

**Critical Architectural Note:** Truto does *not* retry, throttle, or apply backoff on rate limit errors automatically. Doing so inside an integration proxy leads to opaque timeouts and broken agent execution traces. For more on this pattern, refer to our guide on [how to handle third-party API rate limits](https://truto.one/how-to-handle-third-party-api-rate-limits-when-an-ai-agent-is-scraping-data/). When Torii returns a 429, Truto passes that error directly back to the caller. Truto normalizes the upstream rate limit information into standardized HTTP headers per the IETF specification:

*   `ratelimit-limit`: The maximum allowed requests.
*   `ratelimit-remaining`: The number of requests left in the current window.
*   `ratelimit-reset`: The time at which the rate limit window resets.

The caller (your agent's execution loop) is strictly responsible for inspecting these headers, invoking a sleep or exponential backoff, and retrying the tool call.

### The Catalog vs. Tenant Dichotomy

Torii separates the concept of its global software catalog from the apps actually installed in a tenant's environment. The `list_all_torii_apps` endpoint returns only the apps currently active or discovered within the specific organization. However, the `torii_apps_search` endpoint searches Torii's global database of known software. If an agent is tasked with adding a new contract for a tool the company hasn't historically used, it must first search the catalog to find the correct `idApp` before it can attach a contract to it.

## Auto-Generating Torii Tools via Truto

Every integration on Truto is represented as a comprehensive JSON object mapping the underlying API's behavior. We define `Resources` (like Users, Apps, Contracts) and `Methods` on those resources (List, Get, Create, Update).

Truto handles the authentication handshake, API schema normalization, and pagination cursors. To expose these to an LLM, Truto provides a `/tools` endpoint that translates these Methods into fully described, JSON-schema-compliant function definitions, making it one of the [best unified APIs for LLM tool calling](https://truto.one/the-best-unified-apis-for-llm-function-calling-ai-agent-tools-2026/).

To fetch your Torii tools, you simply make a GET request to your integrated account:

```bash
GET https://api.truto.one/integrated-account/<torii_account_id>/tools
Authorization: Bearer <truto_api_key>
```

This returns an array of proxy APIs with their descriptions and query schemas perfectly formatted for LLM ingestion.

## Hero Tools for Torii AI Agents

To orchestrate SaaS lifecycles effectively, you do not need to expose all 50+ Torii endpoints to the LLM. Doing so often pollutes the context window. Instead, you should provide a highly curated set of high-leverage tools. 

Here are the critical "hero tools" to inject into your Torii agent.

### get_single_torii_user_by_id

Retrieves the core identity record for an employee. The agent relies on this to inspect the `lifecycleStatus` (e.g., Active, Suspended, Deleted) and verify external identity source state (`isDeletedInIdentitySources`).

*Usage Note:* Agents should always use this to confirm a user's current state before attempting any write operations or offboarding workflows.

> "Retrieve the Torii profile for the user ID 8f72a1b9 to check if their lifecycle status is already marked as offboarded."

### update_a_torii_user_by_id

Modifies a specific user in Torii. This is the primary execution tool for HR-driven IT lifecycle changes. It requires the `lifecycleStatus` in the request body.

*Usage Note:* When offboarding, the agent must change the status here. The response returns the updated state confirming the execution.

> "Update the Torii user ID 8f72a1b9 and set their lifecycleStatus to Suspended."

### list_all_torii_user_applications

Lists the application junction objects for a specific user. Requires `id_user`. This returns the critical `isUserRemovedFromApp` and `state` fields for every app tied to that identity.

*Usage Note:* Because Torii tracks app assignments separately from the user record, the agent must pull this list to generate a comprehensive offboarding checklist or security audit.

> "List all user applications associated with Torii user ID 8f72a1b9 so I can verify which SaaS tools they still have active access to."

### torii_apps_search

Searches Torii's global catalog of software using a query string. Returns the global `id`, `category`, and `url`.

*Usage Note:* If an agent is processing an inbound software request from Jira, it must use this tool to map the plain-text software name (e.g., "Figma") to the canonical Torii app ID before attempting to log a contract.

> "Search the Torii app catalog for 'Figma' and return the official application ID and category."

### list_all_torii_contracts

Returns an array of all financial contracts in the organization, including `id`, `name`, `status`, and `idApp`.

*Usage Note:* Used heavily by financial and procurement agents to reconcile upcoming renewals against actual utilization data.

> "List all Torii contracts so I can identify which ones are currently marked as Active and tied to the Figma application ID."

### update_a_torii_contract_by_id

Modifies contract details. Supports updating the status and numeric/object-based currency fields.

*Usage Note:* An agent processing a renewal via email or ticketing system can invoke this to update the contract value or push the expiration date forward.

> "Update the Torii contract ID c991a2 to reflect a renewed status and adjust the currency amount to 15000."

For the complete inventory of available methods, supported properties, and granular schema details, refer to the [Torii integration page](https://truto.one/integrations/detail/torii).

## Workflows in Action

Exposing these tools to an LLM unlocks multi-step, autonomous operations that previously required hours of manual point-and-click work from sysadmins. Here is how these tools sequence together in production.

### 1. Autonomous Employee Offboarding

When a termination ticket hits the IT queue, an agent can autonomously handle the SaaS teardown checklist.

> "A departure ticket was created for jsmith@company.com. Find their Torii user ID, audit all the applications they currently have access to, and update their Torii lifecycle status to suspended."

**Execution Steps:**
1.  **`list_all_torii_users`**: The agent searches for the email `jsmith@company.com` to extract the Torii `id`.
2.  **`list_all_torii_user_applications`**: The agent passes the extracted `id_user` to pull an array of all SaaS apps currently assigned to the user.
3.  *(Internal Logic)*: The agent formats this list of active apps into an audit log to paste back into the IT ticket.
4.  **`update_a_torii_user_by_id`**: The agent executes the state change, mutating the `lifecycleStatus` to `Suspended`.

**Result:** The user is suspended globally in Torii, and the IT admin receives an automated comment on their ticket detailing exactly which applications the user possessed at the time of suspension.

### 2. Shadow IT Discovery & Contract Mapping

Financial controllers often struggle to map rogue software expenses to official catalog items. An agent can read expense data and map it directly into Torii.

> "We found an unmanaged expense for 'Lucidchart'. Search the Torii catalog to find the official ID for this app, then check if we already have an active contract for it in our system."

**Execution Steps:**
1.  **`torii_apps_search`**: The agent queries `q=Lucidchart` and retrieves the canonical `id` from Torii's global database.
2.  **`list_all_torii_contracts`**: The agent retrieves the organization's contracts.
3.  *(Internal Logic)*: The agent filters the contract array looking for the `idApp` that matches the Lucidchart ID.

**Result:** The agent replies informing the controller whether this software is genuinely rogue (no contract exists) or if it simply represents off-contract spend on an existing approved vendor.

## Building Multi-Step Workflows

To build a resilient AI agent, you must construct an execution loop capable of passing tool schemas to the model, catching the model's tool calls, invoking the Truto API, and feeding the result back into the prompt context. 

Crucially, this loop must intercept `429` rate limit errors and utilize the `ratelimit-reset` header, as Truto will not absorb these errors for you.

Below is an architectural example using TypeScript and the official `@langchain/core` primitives. We assume the use of a utility manager (like the `TrutoToolManager` from our `truto-langchainjs-toolset`) to handle the raw `/tools` fetching.

```typescript
import { ChatOpenAI } from "@langchain/openai";
import { TrutoToolManager } from "truto-langchainjs-toolset";
import { HumanMessage, AIMessage, ToolMessage } from "@langchain/core/messages";

async function runToriiAgent(prompt: string, toriiAccountId: string) {
  // 1. Initialize the LLM
  const llm = new ChatOpenAI({
    modelName: "gpt-4o",
    temperature: 0,
  });

  // 2. Fetch Torii tools from Truto
  const toolManager = new TrutoToolManager(process.env.TRUTO_API_KEY);
  const tools = await toolManager.getTools(toriiAccountId);
  
  // Bind the tools to the LLM
  const llmWithTools = llm.bindTools(tools);

  // 3. Setup conversation state
  const messages = [new HumanMessage(prompt)];

  console.log("Starting autonomous Torii agent execution...");

  // 4. The Agent Execution Loop
  while (true) {
    const response = await llmWithTools.invoke(messages);
    messages.push(response);

    // If the model decides no more tools are needed, break the loop
    if (!response.tool_calls || response.tool_calls.length === 0) {
      console.log("\nFinal Output:", response.content);
      break;
    }

    // 5. Execute requested tool calls
    for (const toolCall of response.tool_calls) {
      console.log(`Executing Torii Tool: ${toolCall.name}`);
      
      const toolToRun = tools.find((t) => t.name === toolCall.name);
      if (!toolToRun) continue;

      let toolResultStr = "";

      try {
        // Execute the proxy API call via the Truto tool definition
        const toolResult = await toolToRun.invoke(toolCall.args);
        toolResultStr = JSON.stringify(toolResult);
        
      } catch (error: any) {
        // 6. Explicitly handle HTTP 429 Rate Limits from Torii via Truto
        if (error.response && error.response.status === 429) {
          console.warn(`[Rate Limit Hit] Torii returned 429 for ${toolCall.name}.`);
          
          const headers = error.response.headers;
          const resetTimeMs = parseInt(headers['ratelimit-reset'], 10) * 1000;
          const now = Date.now();
          const sleepDuration = Math.max(0, resetTimeMs - now) + 1000; // buffer

          console.log(`Sleeping for ${sleepDuration}ms based on ratelimit-reset header...`);
          await new Promise(resolve => setTimeout(resolve, sleepDuration));

          // Instruct the LLM that the tool failed due to limits and it should try again
          toolResultStr = JSON.stringify({ 
            error: "Rate limit exceeded. The system paused. Please retry your tool call immediately." 
          });
        } else {
          // Handle 400s, 401s, etc.
          toolResultStr = JSON.stringify({ error: error.message });
        }
      }

      // Feed the result (or the rate limit instruction) back to the LLM
      messages.push(new ToolMessage({
        tool_call_id: toolCall.id,
        content: toolResultStr,
      }));
    }
  }
}

// Execute an audit workflow
runToriiAgent(
  "List all Torii users, find the user named 'Alex Chen', and then list all their applications.", 
  "torii_acct_8891abc"
);
```

### Understanding the Architecture

```mermaid
sequenceDiagram
    participant User
    participant Agent as LLM Framework
    participant Truto as Truto /tools API
    participant Torii as Torii Upstream API

    User->>Agent: "Offboard user Alex Chen"
    Agent->>Truto: GET /integrated-account/{id}/tools
    Truto-->>Agent: Returns JSON Schema (list_all_torii_users, etc.)
    Agent->>Agent: LLM analyzes schemas and generates tool_call
    Agent->>Truto: POST proxy execute (list_all_torii_users)
    Truto->>Torii: Normalized API Request
    Torii-->>Truto: 200 OK (User Data)
    Truto-->>Agent: JSON Tool Response
    Agent->>Agent: LLM decides to execute update_a_torii_user_by_id
    Agent->>Truto: POST proxy execute (update_a_torii_user)
    Truto->>Torii: Normalized Write Request
    alt Rate Limit Reached
        Torii-->>Truto: 429 Too Many Requests
        Truto-->>Agent: 429 + ratelimit-reset headers
        Agent->>Agent: Parses headers, triggers sleep()
        Agent->>Truto: Retries POST proxy execute
    end
    Torii-->>Truto: 200 OK (User Updated)
    Truto-->>Agent: JSON Tool Response
    Agent-->>User: "Alex Chen has been suspended."
```

By separating the tool definition from the LLM execution logic, you ensure that your agent stays agnostic to Torii's specific authentication mechanisms and pagination formats, interacting solely with clean, standardized JSON objects.

## Moving from Script to Production

Attempting to build and maintain custom wrappers for the Torii API will trap your engineering team in a perpetual cycle of reading vendor docs, updating JSON schemas, and fighting edge cases around pagination and endpoint routing. 

By using Truto's Unified API and Proxy Architecture, you instantly generate AI-ready tools that map perfectly to the underlying SaaS data models. You retain full control over your agent's execution loop and rate limit handling, without maintaining the integration boilerplate.

> Stop burning engineering cycles maintaining complex integration schemas. Let Truto handle the boilerplate so you can focus on building intelligent agent workflows.
>
> [Talk to us](https://cal.com/truto/partner-with-truto)
