Connect CompanyCam to AI Agents: Automate billing and checklists
Give your AI agent CompanyCam tools.
Connect CompanyCam to AI Agents using Truto's tool endpoint. Fetch strict schemas, handle rate limits natively, and orchestrate complex field service tasks like invoicing and advanced checklists.
In this guide
- 01Understand CompanyCam API Quirks
- 02Fetch Tools via Truto
- 03Bind Tools to your Agent
- 04Implement Rate Limit Handling
- 05Execute Multi-Step Workflows
The guide
Learn how to connect CompanyCam to AI Agents using Truto. Automate site checklists, invoice generation, and project workflows with code examples.
You want to connect CompanyCam to an AI agent so your system can independently track site visuals, complete field checklists, generate invoices, and manage project workflows based on real-time field data. Here is exactly how to do it using Truto's /tools endpoint and SDK, bypassing the need to build a custom integration from scratch.
Giving a Large Language Model (LLM) read and write access to your CompanyCam instance is a significant engineering challenge. You either spend sprints 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 CompanyCam to ChatGPT, or if you are building on Anthropic's models, read our guide on connecting CompanyCam to Claude. For developers building custom autonomous workflows, you need a programmatic way to fetch these tools and bind them directly to your agent framework.
This guide breaks down exactly how to fetch AI-ready tools for CompanyCam, bind them natively to an LLM using frameworks like LangChain, LangGraph, CrewAI, or the Vercel AI SDK, and execute complex field-service operations. For a broader look at the architecture behind this design pattern, refer to our research on architecting AI agents and the SaaS integration bottleneck.
The Engineering Reality of the CompanyCam API
Giving an LLM access to external APIs looks trivial in a quick prototype. You write a fetch wrapper, add an @tool decorator, and move on. In production against complex vertical SaaS platforms like CompanyCam, this approach breaks down quickly.
CompanyCam's API introduces several domain-specific integration challenges that violate standard REST assumptions. If you hardcode these raw endpoints into your agent's context, you will spend your time writing defensive data parsers instead of improving your model's reasoning capabilities.
Asynchronous Checklist Instantiation
When an agent wants to apply a checklist template to a project, it makes a call to create the advanced checklist from a template. In most systems, this is a synchronous operation. In CompanyCam, checklist items populate asynchronously. The API returns the new checklist object immediately, but with a flag is_populating: true, along with a background job ID.
If an LLM attempts to immediately execute a follow-up tool call to fill out the checklist fields, the request will fail because the field tree does not exist yet. Your integration layer must abstract this state, or your agent loop must be explicitly programmed to handle polling, backoffs, and state verification before mutating the checklist.
Divergent Taxonomies: Tags vs. Labels
Standard LLMs struggle with overlapping but distinct categorization taxonomies. In CompanyCam, there are "Labels" and there are "Tags". Labels are applied exclusively to projects. Tags are applied exclusively to photos (media).
If you expose raw API access, an agent will inevitably attempt to apply a "Tag" to a project, resulting in a 400 error. By exposing strictly typed, intent-driven tools (e.g., create_a_company_cam_project_label vs create_a_company_cam_photo_tag), you prevent the model from hallucinating invalid taxonomy assignments.
The Ambiguity of Project State
CompanyCam enforces a strict state machine for projects. Projects can be active, archived, or deleted. Archiving a project hides it from the active list but keeps it intact. Deleting a project is a soft-delete that discards it. The API requires completely different operational paths for these states (projects.archive vs projects.delete, and recovering requires project_archives.delete vs projects.restore). Without a unified tool abstraction, your agent will constantly confuse archive and delete verbs, leading to orphaned projects or failed API requests.
Fetching CompanyCam Tools (The Architecture)
Instead of building individual endpoints, Truto maps CompanyCam's API into a standardized set of Resources and Methods. These proxy APIs handle authentication, mapping, and schema definitions.
By querying the GET /integrated-account/<id>/tools endpoint, you retrieve an array of JSON objects containing the name, description, and strict JSON Schema for every available CompanyCam method. Frameworks like LangChain can consume this array directly and convert it into native tool bindings.
Rate Limits and State Management
It is critical to understand how infrastructure boundaries work here. Truto does not retry, throttle, or apply backoff logic on rate limit errors. When CompanyCam's API returns an HTTP 429 Too Many Requests, Truto passes that error directly to the caller.
However, Truto normalizes the upstream rate limit information into standardized IETF headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset). The caller (your agent framework) is responsible for reading these headers, pausing execution, and applying appropriate retry or backoff logic.
Hero Tools for CompanyCam
Here are the highest-leverage tools available for building CompanyCam AI agents. By utilizing these tools, your agent can orchestrate everything from initial project creation to final invoicing.
Get Single Project by ID
Retrieves the complete context of a project, including jobsite coordinates, primary contact data, status, and share URLs. This is the foundational context gathering tool for any agent operating on a job site.
"Look up the jobsite details for project ID 847291. I need the exact geofence coordinates and the primary contact's phone number."
List All Project Photos
Fetches the photo inventory for a specific project. Crucially, this returns the URI variants (thumbnail, web, original), the captured_at timestamp, creator info, and the exact jobsite coordinates where the photo was taken (derived from EXIF data).
"Retrieve all photos captured on the Smith Roofing project yesterday. Filter for photos that have the 'damage' tag attached to them."
Create a Project Document
Uploads a document (like a PDF report or a text summary) and attaches it to a specific project. This is highly useful when your agent generates a summary report or a site inspection PDF and needs to persist it to the CompanyCam record.
"Take the inspection summary I just generated, format it as a text file named 'inspection_summary.txt', and attach it to project ID 99283."
Create an Advanced Checklist from Template
Instantiates one of the company's checklist templates onto a specific project. This triggers the asynchronous background job to populate the fields.
"Initialize the 'Standard Roof Inspection' checklist template on the new commercial project we just created."
Update Project Advanced Checklist
Sets answers and completion state on specific fields within an advanced checklist. Agents use this to programmatically check off tasks or insert extracted data (e.g., measurements derived from photos) directly into the checklist.
"Update the roof inspection checklist. Set the 'Shingle Condition' field to 'Poor' and mark the 'Gutter Check' section as completed."
Create an Invoice
Generates a draft invoice on a project. Contact fields automatically prefill from the project data. Agents can use this to stage billing workflows immediately after a project checklist is marked complete.
"Draft a new invoice for the completed kitchen remodel project. Leave it in draft status for the account manager to review before sending."
To view the complete inventory of available endpoints and their exact JSON schemas, review the CompanyCam integration page.
Building Multi-Step Workflows
To execute a workflow, your agent needs to fetch the tools, bind them, and enter a reasoning loop. Because Truto normalizes the rate limit headers, you can intercept 429s in your tool execution logic and pause the agent natively.
Here is how you orchestrate this in TypeScript using the @trutohq/truto-langchainjs-toolset and LangChain.
import { ChatOpenAI } from "@langchain/openai";
import { TrutoToolManager } from "@trutohq/truto-langchainjs-toolset";
import { HumanMessage } from "@langchain/core/messages";
async function runCompanyCamAgent(prompt: string, integratedAccountId: string) {
// Initialize the LLM
const llm = new ChatOpenAI({
modelName: "gpt-4o",
temperature: 0,
});
// Fetch tools from Truto's /tools endpoint
const toolManager = new TrutoToolManager({
trutoToken: process.env.TRUTO.API_KEY,
});
const tools = await toolManager.getTools(integratedAccountId);
const llmWithTools = llm.bindTools(tools);
const messages = [new HumanMessage(prompt)];
while (true) {
const response = await llmWithTools.invoke(messages);
messages.push(response);
if (!response.tool_calls || response.tool_calls.length === 0) {
// The agent has finished reasoning and returned a final answer
return response.content;
}
for (const toolCall of response.tool_calls) {
try {
// Execute the tool logic against the CompanyCam API via Truto
const toolResult = await toolManager.executeTool(toolCall);
messages.push({
role: "tool",
content: JSON.stringify(toolResult),
tool_call_id: toolCall.id,
});
} catch (error: any) {
// Truto passes 429s directly. The framework must handle the backoff.
if (error.status === 429) {
const resetTime = error.headers['ratelimit-reset'];
const waitMs = (parseInt(resetTime) * 1000) - Date.now();
console.log(`Rate limited. Pausing execution for ${waitMs}ms`);
await new Promise(resolve => setTimeout(resolve, waitMs));
// Re-inject a message telling the agent to retry
messages.push({
role: "tool",
content: "Error: 429 Too Many Requests. The system paused and recovered. Please retry the exact tool call.",
tool_call_id: toolCall.id,
});
} else {
// Feed standard errors back to the model for self-correction
messages.push({
role: "tool",
content: `Error executing tool: ${error.message}`,
tool_call_id: toolCall.id,
});
}
}
}
}
}This loop provides safety. If the LLM hallucinates an invalid field type for a custom checklist update, the API rejects it, Truto passes the exact 400 Bad Request message, and the agent reads the schema validation error to try again.
Workflows in Action
When you collapse CompanyCam's API complexity behind discrete tool calls, agents can chain operations that would normally require manual data entry across multiple dashboards.
Scenario 1: Automated Invoicing from Field Checklists
Project managers often wait days for field technicians to submit manual completion reports before billing. An AI agent can monitor checklist progress and automatically draft invoices as soon as the work is validated.
"Check the status of the 'HVAC Install' checklist on project ID 7721. If all sections are marked complete, compile a summary of the work, attach it as a project document, and generate a draft invoice for the project."
get_single_company_cam_project_advanced_checklist_by_id: The agent fetches the checklist and verifies thatcompleted_atis set and all required fields evaluate to true.create_a_company_cam_project_document: The agent generates a completion summary text file based on the checklist answers and uploads it to the project record.create_a_company_cam_invoice: The agent drafts a new invoice on the project. Because it relies on the unified tool, it does not need to look up the customer's billing address—CompanyCam prefills it based on theproject_id.
sequenceDiagram
participant User as User Prompt
participant LLM as LangChain Agent
participant Truto as Truto API
participant Upstream as CompanyCam API
User->>LLM: "Check status and generate invoice for project 7721"
LLM->>Truto: call get_single_company_cam_project_advanced_checklist_by_id
Truto->>Upstream: GET /v2/projects/7721/advanced_checklists/...
Upstream-->>Truto: Checklist JSON (completed: true)
Truto-->>LLM: Return checklist state
LLM->>Truto: call create_a_company_cam_project_document
Truto->>Upstream: POST /v2/projects/7721/documents
Upstream-->>Truto: Document ID
Truto-->>LLM: Return success
LLM->>Truto: call create_a_company_cam_invoice
Truto->>Upstream: POST /v2/invoices
Upstream-->>Truto: Invoice JSON (Draft)
Truto-->>LLM: Return invoice ID
LLM-->>User: "Summary document attached and draft invoice created."Scenario 2: Intelligent Project Initialization
When a new commercial client is onboarded, dispatchers have to manually structure the CompanyCam project, tag the property, assign the crew, and apply the correct reporting templates.
"Initialize a new project for 'Acme Corp HQ Remodel'. Apply the 'Commercial Grade' label to the project. Add user ID 1042 as the assigned manager, and start the 'Commercial Safety Audit' advanced checklist template on it."
create_a_company_cam_project: The agent creates the project via a find-or-update operation, ensuring no duplicates exist at the specified jobsite.create_a_company_cam_project_label: The agent applies the specific string label to the project.update_a_company_cam_project_assigned_user_by_id: The agent assigns the specific user ID to the project, triggering automated push notifications to the user's mobile device.create_a_company_cam_project_advanced_checklists_from_template: The agent triggers the background job to build the safety audit checklist on the newly created project.
Moving Forward with Agent Automation
Writing defensive logic to handle background jobs, distinct metadata taxonomies, and custom state machines drains engineering time. AI agents require stable, tightly scoped tools with strict schemas to operate safely on production data.
By leveraging a unified API layer to provide these schemas dynamically, you shift the burden of maintaining API shapes, pagination loops, and authentication lifecycles off of your core application logic. Your engineers can focus on improving the agent's prompt reasoning, while the infrastructure handles the execution layer natively.
FAQ
- How do AI agents handle rate limits when calling CompanyCam?
- Truto passes HTTP 429 errors directly to the caller and normalizes upstream rate limit information into standardized IETF headers. Your AI agent framework is responsible for reading these headers and pausing execution.
- Can an AI agent immediately update an advanced checklist after creating it from a template?
- No. When applying a checklist template in CompanyCam, the items populate asynchronously. The API returns an is_populating flag. The agent must handle this state before attempting to write answers to the checklist fields.
- Labels are exclusively applied to projects, while Tags are exclusively applied to photos. If an AI agent attempts to mix these taxonomies, the API will return a 400 error.
- Which frameworks can I use with Truto's CompanyCam tools?
- Truto's /tools endpoint provides framework-agnostic JSON schemas that work seamlessly with LangChain, LangGraph, CrewAI, Vercel AI SDK, and other major agent orchestration frameworks.