Skip to content

Connect Dvinci to AI Agents: Orchestrate applicant tracking tasks

Uday Gajavalli Uday Gajavalli 10 min read AI & Agents
TrutoFor teams building AI agents

Give your AI agent Dvinci tools.

Connect Dvinci to AI Agents using Truto's /tools endpoint. Bypass custom API integration by binding native Dvinci tools to LangChain or CrewAI, orchestrating job postings, applications, and hiring requests autonomously.

In this guide

  1. 01Initialize the Truto Tool Manager
  2. 02Fetch Dvinci Tools
  3. 03Bind Tools to the Agent
  4. 04Execute and Handle Rate Limits

The guide

A complete developer guide to connecting Dvinci to AI Agents using Truto. Learn how to bind Dvinci tools to your LLM and build autonomous ATS workflows.

You want to connect Dvinci to an AI agent so your system can independently read applicant tracking data, update application statuses, extract resume PDFs, and orchestrate hiring requests based on historical context. Here is exactly how to do it using Truto's /tools endpoint and SDK, bypassing the need to build and maintain a custom integration from scratch.

Giving a Large Language Model (LLM) read and write access to your Dvinci Applicant Tracking System (ATS) is an engineering headache. You either spend weeks building, hosting, and maintaining a custom connector, or you use a managed infrastructure layer that handles the boilerplate for you. If your team uses ChatGPT, check out our guide on connecting Dvinci to ChatGPT, or if you are building on Anthropic's models, read our guide on connecting Dvinci 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 Dvinci, bind them natively to an LLM using frameworks like LangChain, LangGraph, CrewAI, or the Vercel AI SDK, and execute complex talent acquisition workflows. For a deeper look at the architecture behind this approach, refer to our research on architecting AI agents and the SaaS integration bottleneck.

The Engineering Reality of the Dvinci API

Giving an LLM access to external data sounds simple in a prototype. You write a Node.js function that makes a fetch request and wrap it in an @tool decorator. In production against complex ATS platforms like Dvinci, this approach collapses.

Dvinci's API introduces several specific integration challenges that break standard REST assumptions. If you hardcode these interactions into your agent, you will spend your sprints writing defensive integration code instead of improving your model's reasoning capabilities.

The Application Status State Machine

Standard LLMs are trained to expect flat, intuitive CRUD operations. When an agent wants to move a candidate to the "Interview" stage, it naturally attempts to send a standard PATCH payload like {"status": "interview"} to an application endpoint.

Dvinci does not operate this way. Application statuses are bound to a strict state machine. You cannot arbitrarily patch a string field. You must interact with specific status transition endpoints (e.g., dvinci_applications_change_status) and supply the correct internal identifiers for the target stage. If your agent attempts to skip mandatory stages or provide invalid string values, the API rejects the request. Your agent must understand the schema of allowable transitions rather than guessing REST payloads.

Binary Extraction and Resume Parsing

In talent acquisition workflows, the most valuable context is locked inside attachments - specifically resumes and cover letters. Agents need to extract this text to evaluate candidate fit.

Fetching attachments in Dvinci requires navigating a nested resource hierarchy. You first query the application, retrieve the attachment metadata, and then hit a specialized endpoint (dvinci_application_attachments_get_pdf) to stream the binary data. If you expose the raw Dvinci API directly to an LLM, the model will frequently hallucinate binary conversion logic or attempt to read raw byte streams into its context window, causing immediate token limits to burst.

Audit Trails and Historical Upserts

ATS compliance requires strict audit logging. When an agent performs an action on an application, it often needs to record an entry in the application history. The Dvinci API enforces rigid schemas for history upserts (dvinci_application_history_upsert_entry). An agent cannot just write unstructured notes; it must provide structured objects defining the actor, the timestamp, the exact field changed, and the rationale. Direct API exposure forces the LLM to construct deeply nested, strict JSON structures, increasing the probability of schema validation errors.

Why a Unified Tool Layer Matters for Agent Safety

Before writing a line of integration code, decide what layer your agent talks to. This choice determines how safe your production system will be.

Direct API tools (one tool per raw Dvinci endpoint) look convenient but they push provider quirks directly into the LLM's context. The model has to remember that Dvinci expects specific UUID formats, that attachments require two-step fetching, and that history logs need strict timestamp formatting. Every one of those quirks is a hallucination waiting to happen.

Truto's /tools endpoint collapses the API into an agent-optimized schema. Your agent sees deterministic functions with strict parameter typing.

This provides three concrete safety wins:

  1. Smaller attack surface for hallucination. The LLM only ever chooses from stable function names. It never invents custom URL paths or HTTP headers.
  2. Deterministic input validation. Every tool has a strict [JSON schema](/what-is-llm-function-calling-for-integrations-2. Invalid arguments are rejected before they hit the Dvinci servers, meaning a broken tool call fails fast.
  3. Separation of transport from reasoning. The agent focuses entirely on what to do (e.g., "update the status"), while Truto handles the underlying HTTP transport, authentication headers, and query parameter processing.

A Critical Note on Rate Limits

When scaling autonomous agents, API rate limiting becomes your primary operational bottleneck. It is crucial to understand how Truto handles this layer.

Truto does not retry, throttle, or apply backoff on rate limit errors. When an upstream API like Dvinci returns an HTTP 429 (Too Many Requests), Truto passes that error directly to your caller.

However, Truto normalizes the upstream rate limit information into standardized headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) conforming exactly to the IETF specification. Your agent framework or application logic is strictly responsible for implementing the retry and exponential backoff mechanisms. By providing standardized IETF headers, Truto ensures your backoff logic can be written once and applied across any API, rather than writing custom parsing logic for Dvinci's specific rate limit headers.

sequenceDiagram
  participant Agent as Agent Framework
  participant Truto as Truto API
  participant Upstream as "Dvinci API"

  Agent->>Truto: Call list_all_dvinci_applications
  Truto->>Upstream: GET /applications
  Upstream-->>Truto: HTTP 429 Too Many Requests
  Truto-->>Agent: HTTP 429 (ratelimit-reset, ratelimit-remaining)
  Note over Agent: Agent executes <br>exponential backoff
  Agent->>Truto: Retry list_all_dvinci_applications
  Truto->>Upstream: GET /applications
  Upstream-->>Truto: HTTP 200 OK
  Truto-->>Agent: JSON Response

Hero Tools for Dvinci

Truto exposes the Dvinci API as a comprehensive suite of structured tools. Rather than overwhelming your LLM context with hundreds of endpoints, you should provide only the tools necessary for the specific workflow. Here are the highest-leverage hero tools for automating applicant tracking.

list_all_dvinci_job_openings

This tool allows the agent to pull down all active job requisitions. It handles the underlying pagination, allowing the agent to filter openings by department, location, or status.

Contextual usage: Agents use this to determine if a specific role is currently open before attempting to associate a new candidate application with it.

"Fetch all currently open engineering job requisitions in the Berlin office and summarize the core requirements for each."

list_all_dvinci_applications

This tool retrieves candidate applications. It is the primary read mechanism for the ATS, returning candidate metadata, current pipeline stages, and application IDs.

Contextual usage: When triggered by a daily cron job or an incoming email, the agent uses this tool to scan for new applications that have not yet been reviewed.

"Find all applications submitted in the last 24 hours that are currently in the 'New' status."

dvinci_application_attachments_get_pdf

This tool safely retrieves the binary PDF data of an application attachment (like a resume) and converts the metadata into a usable format, sparing the LLM from attempting to parse raw byte streams directly.

Contextual usage: This is vital for resume screening. The agent fetches the PDF text content to perform semantic matching against the job description.

"Retrieve the resume PDF for application ID 84920 and extract the candidate's work history."

dvinci_applications_change_status

This tool executes a state transition for a specific candidate application, moving them forward or backward in the hiring pipeline.

Contextual usage: After evaluating a resume, the autonomous screener uses this tool to move qualified candidates to the 'Screening Call' phase, or reject unqualified ones.

"Change the status of application ID 84920 to 'Rejected' and append a note stating they lack the required React experience."

dvinci_application_history_upsert

This tool writes structured audit logs to an application's history. It ensures compliance by recording exactly when an AI agent made a decision and the reasoning behind it.

Contextual usage: Whenever your agent changes a status or reviews a document, it must call this tool to leave an immutable trail of its decision-making process.

"Add a history entry to application ID 84920 noting that the automated resume screener evaluated the profile and found a 95% match with the job description."

create_a_dvinci_hiring_request

This tool initiates the headcount approval process by generating a new hiring request within Dvinci.

Contextual usage: Internal HR helper bots use this tool when a department head requests a new hire via Slack or Microsoft Teams. The agent structures the request and submits it for executive approval.

"Create a new hiring request for a Senior Backend Engineer in the Platform team, with a target start date of next month and a salary band of 90k-110k."

To view the complete inventory of available Dvinci tools and their strict JSON schemas, visit the Dvinci integration page.

Workflows in Action

To understand how these tools map to actual business value, let's look at how an AI agent orchestrates them to execute multi-step ATS processes autonomously.

Scenario 1: The Autonomous Resume Screener

Recruiting teams spend hours manually opening PDFs to check for basic qualifications. An AI agent can handle the initial screening pipeline entirely in the background.

"Review all new applications for the Data Scientist role. If they have Python and SQL experience, move them to 'Manager Review'. If not, reject them and log the reason."

  1. list_all_dvinci_job_openings: The agent first queries the job openings to find the internal ID for the "Data Scientist" requisition.
  2. list_all_dvinci_applications: The agent queries for all applications tied to that job ID currently sitting in the "New" status.
  3. dvinci_application_attachments_get_pdf: For each application, the agent extracts the text of the attached resume.
  4. dvinci_applications_change_status: The agent evaluates the resume text. Based on the presence of Python and SQL, it calls this tool to update the status to either "Manager Review" or "Rejected".
  5. dvinci_application_history_upsert: The agent logs its exact reasoning in the application history for audit purposes.

Result: The recruiting team logs into Dvinci in the morning to find a pre-sorted pipeline. Unqualified candidates are rejected with clear audit logs, and qualified candidates are queued up for human review.

Scenario 2: Slack-Triggered Headcount Requests

Engineering managers hate logging into the ATS to request new headcount. They prefer to drop a message in Slack. An agent can bridge this gap.

"I need to hire a mid-level QA tester for the mobile team. Budget is around 75k. Can we get this approved?"

  1. create_a_dvinci_hiring_request: The agent intercepts the Slack message, parses the intent, role (QA tester), department (Mobile), and budget (75k). It maps this unstructured text into the strict JSON schema required by Dvinci and submits the request.
  2. list_all_dvinci_hiring_request_approvers (Additional tool): The agent fetches the required approval chain for the mobile team.

Result: The manager never leaves Slack. The agent creates a fully compliant hiring request in Dvinci and notifies the correct executives that a new headcount approval is pending.

Building Multi-Step Workflows

To build these agents, you need to connect the Truto tools to your LLM framework. This approach is completely framework-agnostic. Whether you are using LangChain, LangGraph, CrewAI, or the Vercel AI SDK, the pattern remains the same: fetch the tools via the API, bind them to the model, and manage the execution loop.

Below is a concrete example using LangChain.js and the TrutoToolManager. This script demonstrates how to fetch the Dvinci tools, bind them to an OpenAI model, and execute a tool call.

Crucially, notice the explicit error handling for the HTTP 429 rate limit error. Because Truto passes the 429 directly back to you, your agent loop must catch this status code, read the IETF headers, and pause execution.

import { ChatOpenAI } from "@langchain/openai";
import { HumanMessage } from "@langchain/core/messages";
import { TrutoToolManager } from "truto-langchainjs-toolset";
 
async function runDvinciAgent() {
  // 1. Initialize the Truto Tool Manager with your Integrated Account ID
  const toolManager = new TrutoToolManager({
    trutoApiKey: process.env.TRUTO_API_KEY,
    integratedAccountId: "your_dvinci_account_id_here"
  });
 
  try {
    // 2. Fetch the tools dynamically from the Truto API
    console.log("Fetching Dvinci tools from Truto...");
    const tools = await toolManager.getTools();
    console.log(`Loaded ${tools.length} Dvinci tools.`);
 
    // 3. Initialize the LLM and bind the tools
    const llm = new ChatOpenAI({
      modelName: "gpt-4o",
      temperature: 0,
    });
    const llmWithTools = llm.bindTools(tools);
 
    // 4. Define the prompt
    const messages = [
      new HumanMessage("Find all open job requisitions and list their titles.")
    ];
 
    // 5. Execute the agent
    console.log("Executing agent...");
    const response = await llmWithTools.invoke(messages);
 
    // 6. Handle tool calls
    if (response.tool_calls && response.tool_calls.length > 0) {
      for (const toolCall of response.tool_calls) {
        console.log(`Agent wants to execute: ${toolCall.name}`);
        
        const selectedTool = tools.find(t => t.name === toolCall.name);
        if (selectedTool) {
          // Execute the actual API call against Dvinci via Truto
          const toolResult = await selectedTool.invoke(toolCall.args);
          console.log("Tool execution result:", toolResult);
        }
      }
    } else {
      console.log("Agent Response:", response.content);
    }
 
  } catch (error: any) {
    // 7. Explicit Rate Limit Handling
    if (error.response && error.response.status === 429) {
      const resetTime = error.response.headers.get('ratelimit-reset');
      console.warn(`[RATE LIMIT HIT] Dvinci API rejected the request. Wait until ${resetTime} before retrying.`);
      // Implement your delay and retry logic here
    } else {
      console.error("Workflow failed:", error);
    }
  }
}
 
runDvinciAgent();

The Agentic Loop

In a real-world LangGraph or CrewAI deployment, the code above sits inside a loop. The agent framework executes the llmWithTools.invoke, processes the JSON response from the tool, appends the result to the message history, and calls the LLM again.

Because Truto normalizes the Dvinci API into strict JSON schemas, the LLM rarely hallucinates the tool arguments. When a rate limit is hit, the framework catches the 429, reads the ratelimit-reset header provided by Truto, pauses the agent, and safely resumes the loop once the window clears. This separation of concerns - Truto handles the schemas and auth, the framework handles the state and retries - is how you build reliable enterprise AI.

Giving AI agents access to your applicant tracking data should not require months of integration engineering. By utilizing a unified tool layer, you remove the burden of auth lifecycles, nested binary extraction quirks, and state machine validations.

Your engineers can focus on crafting the perfect prompts and orchestration logic, while Truto handles the messy reality of the underlying Dvinci API.

Two ways to put Dvinci to work

Truto

For product teams

Give your agent Dvinci tools

Your customers connect their own Dvinci accounts. Your product gets one API and MCP tools for Dvinci, through Truto.

FAQ

Does Truto automatically handle Dvinci API rate limits?
No. Truto passes HTTP 429 rate limit errors directly back to the caller. However, Truto normalizes the rate limit data into standard IETF headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) so your agent framework can easily implement retry and backoff logic.
Can I use these Dvinci tools with any LLM framework?
Yes. Truto's tools are framework-agnostic. You can bind them to LangChain, LangGraph, CrewAI, the Vercel AI SDK, or any custom architecture that supports JSON schema function calling.
How does the agent handle extracting text from candidate resumes?
Truto provides specific hero tools like `dvinci_application_attachments_get_pdf` that safely retrieve the binary PDF data and metadata, preventing the LLM from hallucinating or crashing due to raw byte streams in the context window.
D DvinciAI agent tools Get a sandbox

More from our Blog