Skip to content

Connect HR WORKS to AI Agents: Sync Payroll, Expenses & HR Flows

Learn how to connect HR WORKS to AI agents using Truto's tools endpoint to autonomously orchestrate payroll data, time-off requests, and expense reporting.

Nachi Raman Nachi Raman · · 10 min read
Connect HR WORKS to AI Agents: Sync Payroll, Expenses & HR Flows

You want to connect HR WORKS to an AI agent so your system can autonomously read master employee data, log sick leaves, clock working hours, and sync travel expenses. Here is exactly how to do it using Truto's /tools endpoint and SDK, bypassing the need to build and maintain a custom HR WORKS integration from scratch.

Giving a Large Language Model (LLM) read and write access to a complex Human Resources Information System (HRIS) is an engineering challenge. You either spend months building, hosting, and maintaining a custom connector that handles the unique quirks of the HR WORKS API, or you use a managed infrastructure layer that provides agent-ready tools out of the box. If your team uses ChatGPT, check out our guide on connecting HR WORKS to ChatGPT, or if you are building on Anthropic's models, read our guide on connecting HR WORKS 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 HR WORKS, bind them natively to an LLM using frameworks like LangChain, LangGraph, CrewAI, or the Vercel AI SDK, and execute complex HR workflows. For a broader look at this design pattern across the SaaS landscape, read our research on architecting AI agents and the SaaS integration bottleneck.

The Engineering Reality of the HR WORKS API

Giving an LLM access to external data sounds simple during local prototyping. You write a standard Python or Node.js function that makes a fetch request, wrap it in a @tool decorator, and hand it to the model. In production, against highly specialized enterprise systems like HR WORKS, this naive approach collapses quickly.

HR WORKS operates an API designed for high-volume bulk data synchronization, not conversational, synchronous CRUD operations. Standard LLMs are trained to expect flat REST behaviors - send a POST, get the created record back immediately. If you hardcode standard REST assumptions into your agent, your system will fail. Here are the specific architectural quirks of the HR WORKS API that Truto's tool layer normalizes for you.

Asynchronous Job-Based Writes

Almost every write operation in HR WORKS is asynchronous. If an agent wants to create an absence, a sick leave, or a travel expense report, the API does not return the created record. Instead, the endpoint accepts a bulk data array (even for single records) and returns a jobId.

To know if the write succeeded, the client must poll a specific job endpoint (e.g., GET /v2/absences/jobs/{jobId}). The job remains in a pending state until HR WORKS processes the queue, after which it returns the written records or HTTP 200 responses containing nested write errors. Standard agents lack the state management to correctly implement polling loops. Truto provides specialized *_jobs_get_or_error tools that allow the agent to safely poll these results without crashing when HR WORKS throws intermediate error states.

Strict Date Intervals and Interval Splitting

When fetching list data like absences, remote work logs, or working times, HR WORKS enforces aggressive bounding box constraints. Almost all list endpoints require explicit beginDate and endDate parameters.

Furthermore, these dates cannot span more than a single year. Worse, if you request data split by specific intervals (e.g., interval=days), HR WORKS strictly limits the date range to a maximum of 31 days. If an LLM attempts to query "all absences for the last two years" and formats a generic REST payload, the API will reject it outright. The unified tool schema enforces these constraints natively, preventing the LLM from hallucinating invalid temporal ranges.

Non-Standard Pagination and Payload Keying

HR WORKS does not return flat arrays for its list resources. Instead, paginated responses are returned as a single JSON object keyed by the person identifier (often the license number or personnel number), grouping the data underneath. Additionally, HR WORKS hardcodes its page sizes (typically 50 or 150 persons per page) and ignores arbitrary limit parameters passed by the client.

An AI agent trying to parse these dynamically keyed objects directly will rapidly burn through context windows and struggle to extract array subsets. Truto's proxy layer flattens these structures into predictable, documented JSON schemas that LLMs can ingest deterministically.

Why a Unified Tool Layer Matters for Agent Safety

Before writing a line of code, you must decide what layer your agent actually communicates with. This architectural choice determines how resilient your production system will be.

Direct API tools (mapping one tool to one raw HR WORKS endpoint) push vendor quirks directly into the LLM's prompt context. The model has to remember that HR WORKS needs asynchronous job polling, strict 31-day bounds for daily intervals, and dynamic object keys. Every one of those requirements increases the cognitive load on the LLM, leading to hallucinations.

A unified tool layer abstracts these quirks behind stable schemas. Your agent sees standardized functions like list_all_hr_works_absences and create_a_hr_works_absence. That provides three concrete safety wins:

  1. Reduced Hallucination Surface: The LLM selects from a stable list of rigidly defined functions. It never invents raw HR WORKS payload structures or guesses pagination cursors.
  2. Deterministic Validation: Every Truto tool enforces a strict JSON schema. If the LLM tries to query a 60-day range with a daily interval, the schema rejects the invalid argument before it ever touches the upstream API, failing fast.
  3. Isolated Integration Logic: You can swap or update the underlying API mappings in Truto without deploying new code or retraining the agent's core prompt logic.

Hero Tools for HR WORKS AI Agents

Truto exposes dozens of endpoints as discrete tools for HR WORKS. For agentic workflows, you want to focus on high-leverage operations that map directly to HR admin, payroll, and employee lifecycle tasks. Here are the hero tools you should make available to your agent.

list_all_hr_works_person_master_data

This tool retrieves the complete master data for employees, including contact details, addresses, bank accounts, employment status, and organizational hierarchy. It is the primary discovery tool an agent uses to map a natural language name to a specific person identifier required by other endpoints.

"Find the personnel number, current organization unit, and active bank account details for employee Jane Doe."

list_all_hr_works_absences

This tool lists absences per person within a specific date range. It requires beginDate and endDate and can split the output by days, weeks, or months. This is essential for agents calculating payroll readiness or answering queries about team availability.

"Pull the absence records for John Smith for the month of October, breaking down the totals by absence type to see how many sick days versus vacation days were taken."

create_a_hr_works_absence

This is the primary write tool for booking time off. It requires the absence type, start and end dates, status, and the personnel number. Because it is asynchronous, it returns a jobId rather than the completed absence record.

"Book a standard vacation absence for personnel number 1042 starting next Monday and ending on Friday. Mark the status as approved."

hr_works_absence_jobs_get_or_error

This is the critical companion tool to the absence creation endpoint. It allows the agent to poll the status of an absence write job using the jobId. Crucially, if HR WORKS returns an HTTP error (like a 429 rate limit or a 5xx), this tool wraps it in a 200 response ({"truto_error": ...}) so the agent's execution loop doesn't crash, allowing it to gracefully retry or report the error.

"Check the status of job ID 98765 to confirm if the vacation request for personnel number 1042 was successfully written to the system."

create_a_hr_works_expense_report

This tool allows the agent to submit travel expense reports in bulk. It requires the person identifier and the start and end dates of the trip. Agents can use this to process structured text from a scanned receipt or an email and push it directly into the HR WORKS expense queue.

"Create a travel expense report for personnel number 2055 for the trip between November 1st and November 3rd, and return the job ID for the submission."

create_a_hr_works_person_working_time

This synchronous tool allows an agent to clock a person in or out in real-time. It requires the action (clockIn or clockOut) and the person identifier. It is perfect for chat-based Slack or Teams agents where employees can log their hours conversationally.

"Clock in personnel number 3011 for the day right now, and let me know if the system returns any warnings."

To view the complete inventory of available tools, query schemas, and return types, visit the HR WORKS integration page.

Workflows in Action

Let us look at how these tools combine to automate complete, multi-step HR workflows autonomously.

Scenario 1: Conversational Time-Off Booking

An employee asks an internal Slack bot to book next week off. The agent must resolve the employee's ID, submit the request, and verify it was processed by the asynchronous queue.

"I need to take next Monday through Wednesday off for personal reasons. Please log this vacation request for me."

  1. list_all_hr_works_person_master_data: The agent searches for the Slack user's email to retrieve their specific HR WORKS personnelNumber.
  2. create_a_hr_works_absence: The agent submits the absence payload with the correct dates and the resolved personnel number. HR WORKS accepts the payload and returns a jobId (e.g., job_9921).
  3. hr_works_absence_jobs_get_or_error: The agent waits a moment and polls the job endpoint using job_9921.
  4. The agent receives a success payload confirming the absence was written, and messages the user back in Slack confirming the exact dates are now pending approval in the system.

Scenario 2: Automated Expense Processing

A field technician emails a summary of their travel dates to an internal system. The agent parses the unstructured text and logs the travel report.

"I just got back from the Chicago site visit. I left on Tuesday the 12th and returned on Thursday the 14th. Please file my initial expense report shell."

  1. list_all_hr_works_person_master_data: The agent uses the sender's email to fetch their personnelNumber.
  2. create_a_hr_works_expense_report: The agent formats the payload using the extracted dates (the 12th to the 14th) and submits it to HR WORKS, receiving a jobId in return.
  3. get_single_hr_works_expense_report_job_by_id: The agent polls the job queue until HR WORKS confirms the expense report shell has been created.
  4. The agent responds to the technician with the newly generated expense report ID, prompting them to upload their specific receipts via the HR WORKS portal.

Building Multi-Step Workflows

To build these workflows, you need to connect your agent framework to Truto's /tools endpoint. Truto's architecture is framework-agnostic. Whether you are using LangChain, LangGraph, CrewAI, or the Vercel AI SDK, the integration pattern remains identical: fetch the schema, bind the tools to the LLM, and execute the loop.

Before you write the code, you must understand a critical architectural fact about rate limits. Truto does not retry, throttle, or apply backoff on rate limit errors. If HR WORKS returns an HTTP 429 (Too Many Requests), Truto passes that error directly back to your agent. Truto normalizes the upstream rate limit data into standard IETF headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset).

This is a deliberate design choice. Abstracting rate limits inside the proxy layer hides upstream capacity constraints from your agent. Your agent framework is responsible for reading the ratelimit-reset header and putting the agent to sleep, preventing endless hallucinated retry loops.

Here is how you implement a tool-calling loop using Truto's SDK and LangChain in TypeScript, including proper rate limit handling.

import { ChatOpenAI } from "@langchain/openai";
import { AgentExecutor, createToolCallingAgent } from "langchain/agents";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { TrutoToolManager } from "truto-langchainjs-toolset";
 
async function runHRAgent() {
  // 1. Initialize the LLM
  const llm = new ChatOpenAI({
    modelName: "gpt-4o",
    temperature: 0,
  });
 
  // 2. Fetch HR WORKS tools from Truto for a specific integrated account
  const truto = new TrutoToolManager({
    apiKey: process.env.TRUTO_API_KEY
  });
  
  const accountId = "hr_works_account_xyz123";
  const tools = await truto.getTools(accountId);
 
  // 3. Define the agent prompt
  const prompt = ChatPromptTemplate.fromMessages([
    ["system", `You are an autonomous HR assistant connected to HR WORKS.
      You have access to tools for managing employees, absences, and expenses.
      When creating records, remember that the API returns a jobId. You MUST poll 
      the corresponding job tool to verify the write succeeded.
      If a tool fails due to a rate limit (HTTP 429), you must inspect the error message 
      and stop calling tools until the limit resets.`],
    ["human", "{input}"],
    ["placeholder", "{agent_scratchpad}"],
  ]);
 
  // 4. Bind tools and create the executor loop
  const agent = createToolCallingAgent({ llm, tools, prompt });
  const executor = new AgentExecutor({
    agent,
    tools,
    maxIterations: 10,
    // We do not want LangChain to silently swallow critical API errors
    handleParsingErrors: true,
  });
 
  // 5. Execute the multi-step workflow
  try {
    const result = await executor.invoke({
      input: "Find personnel number for jane.doe@company.com, book her a standard vacation from next Monday to Wednesday, and verify the job completed."
    });
    console.log(result.output);
  } catch (error) {
    // 6. Explicitly handle pass-through HTTP 429 Rate Limits from Truto
    if (error.status === 429) {
      const resetTime = error.headers['ratelimit-reset'];
      console.error(`Rate limit exceeded. Agent must pause until: ${resetTime}`);
      // Implement your framework-specific sleep/backoff logic here
    } else {
      console.error("Agent execution failed:", error);
    }
  }
}
 
runHRAgent();

This pattern keeps the LLM's context window small and focused. The agent orchestrates the logic, Truto manages the authentication, pagination, and unified schemas, and your application handles the flow control based on clear HTTP semantics.

sequenceDiagram
    participant User as End User
    participant Agent as AI Agent
    participant Truto as Truto Tool Layer
    participant HRWorks as HR WORKS API

    User->>Agent: "Book vacation for next week"
    
    Agent->>Truto: Call list_all_hr_works_person_master_data
    Truto->>HRWorks: GET /v2/persons/master-data
    HRWorks-->>Truto: Raw JSON (Keyed by ID)
    Truto-->>Agent: Flattened Unified JSON Schema
    
    Agent->>Truto: Call create_a_hr_works_absence
    Truto->>HRWorks: POST /v2/absences (Bulk Array)
    HRWorks-->>Truto: { jobId: "job_9921" }
    Truto-->>Agent: { jobId: "job_9921" }
    
    loop Polling
        Agent->>Truto: Call hr_works_absence_jobs_get_or_error(job_9921)
        Truto->>HRWorks: GET /v2/absences/jobs/job_9921
        HRWorks-->>Truto: Status: Pending
        Truto-->>Agent: Status: Pending
        Note over Agent: Wait interval
    end
    
    Truto->>HRWorks: GET /v2/absences/jobs/job_9921
    HRWorks-->>Truto: Status: Finished (Success)
    Truto-->>Agent: Status: Finished (Success)
    
    Agent-->>User: "Vacation successfully booked!"

Moving to Production

Connecting AI agents to enterprise systems like HR WORKS is no longer about writing point-to-point API connectors in Node.js. The bottleneck has shifted from raw connectivity to architectural safety, schema stability, and state management.

By leveraging Truto's /tools endpoint, you remove the burden of managing OAuth tokens, normalizing dynamic object keys, and writing defensive JSON parsing logic from your agent's context window. Your LLM focuses entirely on orchestrating HR workflows, while Truto ensures every API call adheres to strict, validated schemas.

Stop writing custom API wrappers for your AI agents and start building autonomous HR operations that scale.

FAQ

How do AI agents handle HR WORKS asynchronous write jobs?
HR WORKS returns a jobId for writes (like absences or expenses). Agents use Truto's `*_jobs_get_or_error` tools to poll the job status securely without crashing if the upstream API throws temporary errors.
Does Truto automatically handle HR WORKS rate limits?
No. Truto passes HTTP 429 rate limit errors directly to the caller, alongside standard IETF headers (`ratelimit-reset`). The AI agent framework is responsible for reading these headers and executing backoff logic.
Can I use frameworks other than LangChain with Truto tools?
Yes. Truto's `/tools` endpoint provides standard JSON schemas that can be natively bound to any agent framework, including LangGraph, CrewAI, AutoGen, and the Vercel AI SDK.
Why shouldn't I build a direct HR WORKS API connector for my LLM?
Direct connectors push upstream API quirks (like strict 31-day interval limits and non-standard JSON keys) into the LLM's context, leading to hallucinations and invalid payloads. Truto abstracts these into predictable schemas.

More from our Blog