Connect Fortnox to AI Agents: Automate Billing and ERP Tasks
A complete engineering guide to connecting Fortnox to AI agents. Learn how to fetch AI-ready tools, handle financial API quirks, and build autonomous workflows.
You want to connect Fortnox to an AI agent so your system can autonomously onboard customers, track suppliers, generate invoices, and manage inventory 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 Fortnox connector from scratch.
Giving a Large Language Model (LLM) read and write access to your ERP and accounting software is an engineering challenge with zero margin for error. You either spend weeks building, hosting, and maintaining a custom connector that deals with Fortnox's strict relational data models, or you use a managed infrastructure layer that handles the boilerplate. If your team uses ChatGPT, check out our guide on connecting Fortnox to ChatGPT, or if you are building on Anthropic's models, read our guide on connecting Fortnox 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 Fortnox, bind them natively to an LLM using LangChain (or any framework like LangGraph, CrewAI, or Vercel AI SDK), and execute complex ERP operations safely. 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 Fortnox API
Giving an LLM access to external accounting 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 ERP systems, this approach collapses.
Fortnox'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.
Strict Financial State Transitions
Standard LLMs are trained to expect that CRUD (Create, Read, Update, Delete) applies universally. Fortnox enforces strict accounting principles. You cannot simply DELETE an invoice once it has been booked. Invoices have strict states (DRAFT, BOOKED, CANCELLED). If an agent attempts to update a booked invoice with standard REST logic, the API will reject it. Your agent must understand that reversing a transaction often requires creating a credit note or explicitly annulling the record, rather than issuing a standard HTTP DELETE request.
Relational Entity Dependencies
Fortnox relies heavily on composite lookups. To create an invoice, you cannot just pass a customer's name or a generic string ID. You must provide a specific CustomerNumber and ArticleNumber. This means an agent cannot simply infer an invoice payload from a user prompt. It must first execute a search query to resolve the customer, then execute a search query to resolve the catalog article, and only then construct the nested InvoiceRows array. Exposing raw OpenAPI specs to an LLM usually results in hallucinations because the model forgets to chain these dependent lookups in the correct order.
Brutal Rate Limiting Rules
Fortnox enforces strict API rate limits per access token to protect their infrastructure. When you hit these limits, Fortnox rejects requests. This is where many custom integrations fail.
Truto does not magically absorb or retry rate limit errors. When Fortnox returns an HTTP 429, 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). This is critical for AI agents: instead of forcing the agent to parse undocumented JSON error bodies to guess when it can try again, your agent framework can intercept the standardized 429 response, read the ratelimit-reset header, and deterministically backoff before resuming its tool execution loop.
Why a Unified Tool Layer Matters for Agent Safety
Before writing a line of integration code, decide what layer your agent talks to. Direct API tools (one tool per raw Fortnox endpoint) look convenient but they push provider quirks into the LLM's context. The model has to remember exactly how Fortnox formats organization numbers, how it handles pagination cursors, and the exact naming conventions of its deeply nested JSON structures.
Truto's unified tool layer collapses these complexities. Your agent sees simple, descriptive function names with strict JSON schemas.
- Smaller attack surface for hallucination. The LLM only ever chooses from stable function names like
create_a_fortnox_invoice. It never invents raw HTTP paths or query string parameters. - Deterministic input validation. Every tool has a strict JSON schema. Invalid arguments are rejected before they hit Fortnox, so a broken tool call fails fast instead of creating corrupt financial records.
- Framework agnostic. The
/toolsendpoint returns definitions that easily map into.bindTools()for LangChain, OpenAI function schemas, or Anthropic tool definitions.
Hero Tools for Fortnox AI Agents
Truto provides a comprehensive suite of Proxy APIs for Fortnox. When you call the /tools endpoint, these methods are translated into highly described JSON schemas optimized for LLM consumption. Here are the highest-leverage tools for automating ERP workflows.
1. list_all_fortnox_customers
Before an agent can generate a quote, order, or invoice, it must resolve the target entity. This tool retrieves a paginated list of customers, sorted by customer number. It allows the agent to filter by email, name, or phone number to find exact matches.
Contextual usage notes: Agents should be instructed to always use this tool to search for a customer by email or name before attempting to create a new one, preventing duplicate records in the ERP.
"Search our Fortnox system to see if we have an active customer record for 'Acme Corp' or the email 'billing@acmecorp.com'."
2. create_a_fortnox_customer
If a customer does not exist, the agent can use this tool to onboard them. It accepts standard customer details and strictly enforces Fortnox's requirement for a valid Name.
Contextual usage notes: The tool returns the newly generated CustomerNumber, which the agent must extract and keep in context for subsequent invoicing tools.
"Create a new active customer record for 'Tech Innovations Inc.' with the organization number 555-1234 and return their new customer number."
3. list_all_fortnox_articles
Invoices in Fortnox require specific line items tied to the company's article catalog. This tool allows the agent to search the catalog and retrieve exact ArticleNumber values.
Contextual usage notes: Because LLMs are prone to hallucinating line-item prices, forcing the agent to fetch the source of truth from the article list ensures the invoice generated matches the agreed-upon catalog pricing.
"Find the article number and current price for our 'Enterprise Consulting Retainer' service in the Fortnox catalog."
4. create_a_fortnox_invoice
This is the core monetization tool. It generates an invoice for a customer by accepting a customer_number, an invoice_date, and a nested array of invoice_rows.
Contextual usage notes: Instruct your agent to construct the invoice_rows array precisely, ensuring each row maps to a valid article number retrieved in a previous step.
"Generate an invoice for customer number 1042 for today's date, adding one row for article number 50 (Consulting) and two rows for article number 12 (Software License)."
5. get_single_fortnox_invoice_by_id
This tool retrieves the full state of a specific invoice. It is heavily utilized in customer support workflows to answer inquiries about billing.
Contextual usage notes: Useful for verifying the status of an invoice (e.g., checking if it is booked, cancelled, or paid) before attempting to send reminders or issue credits.
"Check the status and total balance of Fortnox invoice number 40992 and tell me if it has been booked."
6. list_all_fortnox_suppliers
For accounts payable (AP) automation, agents need to interact with the vendor side of the ledger. This tool lists all suppliers, allowing agents to audit active vendors, retrieve VAT numbers, and verify contact information.
Contextual usage notes: Ideal for vendor risk management workflows or routing AP inquiries to the correct department based on the supplier's active status.
"Retrieve a list of all active suppliers in Fortnox and find the VAT number for 'Office Supplies Direct'."
To view the complete inventory of available proxy tools, schemas, and resource definitions, visit the Fortnox integration page.
Workflows in Action
Standalone tools are useful, but the real power of an AI agent lies in chaining these tools together to execute complex, multi-step workflows. Here is how specific personas use these tools in production.
Scenario 1: Autonomous Quote-to-Cash (Sales Operations)
A sales operations manager needs to convert a won deal in a CRM into a finalized invoice in Fortnox without manual data entry.
"We just closed a deal with 'Globex Corporation'. Ensure they exist as a customer in Fortnox, find the article code for 'Annual SaaS License', and generate a new invoice for one license."
Step-by-step Execution:
- The agent calls
list_all_fortnox_customersfiltering for the name "Globex Corporation". - The ERP returns empty. The agent dynamically pivots and calls
create_a_fortnox_customerusing the details provided in its context, receivingCustomerNumber: 8841in return. - The agent calls
list_all_fortnox_articlesto search for "Annual SaaS License" and extractsArticleNumber: 101. - The agent calls
create_a_fortnox_invoicepassingCustomerNumber: 8841and aninvoice_rowsarray containingArticleNumber: 101.
The Result: The user receives a confirmation that a new customer was onboarded and Invoice #4502 was successfully generated, entirely autonomously.
Scenario 2: Vendor Compliance Audit (Procurement)
A procurement officer needs to verify supplier tax details against internal compliance requirements.
"Audit our Fortnox system for the supplier 'Logistics Partners LLC' and return their full address and VAT number for my compliance report."
Step-by-step Execution:
- The agent calls
list_all_fortnox_suppliersto find the exact match for "Logistics Partners LLC" and retrieves their internalSupplierNumber. - The agent calls
get_single_fortnox_supplier_by_idpassing the extracted ID to pull the full vendor object. - The agent parses the response, extracting the
City,CountryCode, andVATNumber.
The Result: The user receives a formatted compliance summary containing exactly the requested vendor data, isolated from the noise of the raw API response.
Building Multi-Step Workflows
To implement these workflows in code, you need an orchestration layer. While Truto's /tools endpoint serves standard JSON, developers using JavaScript or TypeScript can use the Langchain.js SDK to automatically bind these tools to an agent.
Here is how you orchestrate a multi-step Fortnox workflow using LangGraph, specifically addressing how to handle the inevitable rate limits.
Handling Rate Limits with Truto and AI Agents
When scaling agentic workflows, LLMs execute tools rapidly. Fortnox enforces strict rate limits. When a limit is breached, Fortnox returns a 429. Truto normalizes this upstream error into standardized IETF headers.
Your agent execution loop must catch HTTP 429 errors, inspect the ratelimit-reset header provided by Truto, sleep for the required duration, and then allow the agent to retry the tool call. Truto does not absorb or retry these for you; your code must handle the backoff.
sequenceDiagram
participant User as User Prompt
participant Agent as LangGraph Agent
participant Truto as Truto Unified API
participant Fortnox as Fortnox Upstream API
User->>Agent: "Invoice Acme Corp..."
Agent->>Truto: Call tool list_all_fortnox_customers
Truto->>Fortnox: GET /3/customers
Fortnox-->>Truto: 200 OK
Truto-->>Agent: CustomerNumber: 1045
Note over Agent: Planning next step...
Agent->>Truto: Call tool get_single_fortnox_article_by_id
Truto->>Fortnox: GET /3/articles
Fortnox-->>Truto: 429 Too Many Requests
Truto-->>Agent: 429 (ratelimit-reset: 10)
Note over Agent: Caller catches 429, sleeps 10s
Agent->>Truto: Retry tool get_single_fortnox_article_by_id
Truto->>Fortnox: GET /3/articles
Fortnox-->>Truto: 200 OK
Truto-->>Agent: Article details returnedThe Implementation Code
Below is a conceptual TypeScript example using @langchain/core demonstrating how to fetch Truto tools, bind them to an OpenAI model, and wrap the execution in a resilient loop that respects Truto's normalized rate limit headers.
import { ChatOpenAI } from "@langchain/openai";
import { TrutoToolManager } from "truto-langchainjs-toolset";
// 1. Initialize the Truto Tool Manager with your Integrated Account ID
// This automatically fetches all Fortnox Proxy Methods as LLM tools
const toolManager = new TrutoToolManager({
trutoApiKey: process.env.TRUTO_API_KEY,
integratedAccountId: "your_fortnox_account_id"
});
// 2. Fetch tools and bind them to the LLM
const tools = await toolManager.getTools();
const llm = new ChatOpenAI({ modelName: "gpt-4o", temperature: 0 });
const llmWithTools = llm.bindTools(tools);
// 3. Define a resilient execution loop
async function executeAgentWithBackoff(prompt: string) {
let messages = [{ role: "user", content: prompt }];
while (true) {
const response = await llmWithTools.invoke(messages);
messages.push(response);
// If the LLM decides it has finished planning and needs no more tools
if (!response.tool_calls || response.tool_calls.length === 0) {
return response.content;
}
// Execute tools requested by the LLM
for (const toolCall of response.tool_calls) {
try {
// Find and execute the requested Fortnox tool
const tool = tools.find(t => t.name === toolCall.name);
const toolResult = await tool.invoke(toolCall.args);
messages.push({
role: "tool",
tool_call_id: toolCall.id,
content: JSON.stringify(toolResult)
});
} catch (error: any) {
// 4. Handle Truto's standardized rate limit headers
if (error.status === 429) {
// Extract the IETF standard header passed through by Truto
const resetAfterSeconds = parseInt(error.headers['ratelimit-reset'] || '5', 10);
console.log(`Rate limit hit. Agent sleeping for ${resetAfterSeconds} seconds.`);
await new Promise(resolve => setTimeout(resolve, resetAfterSeconds * 1000));
// Instruct the agent to retry the specific tool call
messages.push({
role: "tool",
tool_call_id: toolCall.id,
content: "Error 429: Rate limit exceeded. Please try this exact tool call again."
});
} else {
// Feed standard API errors (e.g., validation failures) back to the LLM
messages.push({
role: "tool",
tool_call_id: toolCall.id,
content: `Execution failed: ${error.message}`
});
}
}
}
}
}
// Run the workflow
const result = await executeAgentWithBackoff(
"Search for customer 'Globex' and generate an invoice for Article 101."
);
console.log("Agent finished:", result);By flattening Fortnox's strict relational requirements into semantic tools and standardizing upstream rate limits via IETF headers, Truto removes the infrastructure burden of ERP integrations. Your agent can navigate financial lookups securely, backoff gracefully when Fortnox requests it, and execute complex billing workflows without custom pipeline code.
FAQ
- How does Truto handle Fortnox API rate limits?
- Truto does not absorb or automatically retry failed requests due to rate limits. When Fortnox returns an HTTP 429, Truto passes this directly to the caller, mapping the upstream rate limit data to standard IETF headers (`ratelimit-limit`, `ratelimit-remaining`, `ratelimit-reset`). The caller or agent framework is responsible for handling the backoff and retry logic.
- Do I have to define the Fortnox OpenAPI schema for my agent manually?
- No. Truto provides a `/tools` endpoint that automatically exposes Fortnox's resources as LLM-ready JSON schemas. You can bind these dynamically to your agent using frameworks like LangChain, eliminating the need to write or maintain raw API specs.
- Can the AI agent create Fortnox invoices without creating a customer first?
- No. Fortnox requires strict relational entity lookups. To create an invoice, you must supply a valid `CustomerNumber` and `ArticleNumber`. Using Truto's tools, your agent can be prompted to autonomously search for these records first, create them if they are missing, and then generate the final invoice payload.