FrancodesystemsFran<code>systems
Developer guide · API v2 (current)

Integrating with the Holded API v2.

One consolidated base URL, API-key authentication, cursor pagination and structured errors. Here is what v2 covers, how to authenticate, working code examples, and the real pitfalls when you build or migrate a production integration.

What v2 is

One API for the whole ERP

Holded consolidated what used to be several product APIs into a single v2 surface with clear sections. The legacy v1 remains accessible as an archived reference and existing integrations keep working, but all new development targets v2 — and, per Holded's own docs, new integrations should use it directly.

What v2 brings
  • Single consolidated base URL
  • API-key header authentication
  • Cursor pagination (not offset)
  • Consistent structured errors
  • Bulk operations (approve / cancel / delete)
  • Multi-warehouse with in-transit stock
  • Native attachments on every document
  • Webhooks (coming soon)
  • MCP server (coming soon)
Authentication

A single API key, sent as a header

v2 uses a per-account API key rather than an OAuth flow for server-to-server integrations. Generate the key in Holded (Settings → Developers), then send it on every request in the key header. The key inherits the permissions of its account, so scope it deliberately.

  • 1Keep the key server-side — never expose it in a browser or mobile client.
  • 2Store it in a secret manager and rotate it if it is ever exposed.
  • 3Respect rate limits with exponential backoff on 429 responses.
Resources & endpoints

What the v2 surface covers

The API is organised into sections that map to the ERP. Each exposes list, read, create, update and delete operations, plus bulk actions and native attachments where they apply.

Accounting

Ledger entries, expense and accounting accounts, tax rates and numbering series.

Treasury

Banking accounts, cash and bank movements, payments, payment methods and remittances.

Sales

Invoices, estimates, proformas, credit notes, sales orders, receipts and waybills — with bulk operations.

Inventory

Products, services, price lists, warehouses, stock levels and in-transit stock, multi-warehouse CRUD.

Contacts & CRM

Contacts and groups, leads, funnels and configurable pipelines shared with your documents.

Projects, Team & Calendar

Projects and time tracking, employees, contracts, events, tasks and the shared inbox.

Code examples

List invoices and follow the cursor

A minimal read against v2: authenticate with the key header, page with a cursor, and back off on rate limits. The pattern is identical for products, contacts and every other list endpoint.

curl
# List invoices — cursor pagination
curl -s "https://api.holded.com/api/invoicing/v2/documents/invoice?limit=100" \
  -H "accept: application/json" \
  -H "key: <YOUR_API_KEY>"

# Follow the cursor returned in the response
curl -s "https://api.holded.com/api/invoicing/v2/documents/invoice?limit=100&cursor=<NEXT_CURSOR>" \
  -H "accept: application/json" \
  -H "key: <YOUR_API_KEY>"
javascript
// Cursor loop — pseudo-JS, works the same in any language
let cursor = undefined;
const invoices = [];

do {
  const res = await fetch(
    `https://api.holded.com/api/invoicing/v2/documents/invoice?limit=100` +
      (cursor ? `&cursor=${cursor}` : ""),
    { headers: { accept: "application/json", key: process.env.HOLDED_API_KEY } }
  );

  if (res.status === 429) { await backoff(); continue; } // respect rate limits
  const page = await res.json();

  invoices.push(...page.data);
  cursor = page.nextCursor; // undefined when there are no more pages
} while (cursor);
v1 vs v2

What actually breaks when you migrate

It is not just the URL. These structural changes break code silently if you do not review each one.

v1

Several product surfaces (Invoice, CRM, Projects, Team, Accounting APIs)

v2

One consolidated base URL with sections (Accounting, Treasury, Sales, Inventory, Contacts, CRM, Projects, Team & HR, Calendar, Inbox)

Impact

Change your base URL and route prefixes. Mostly find-and-replace, but review every call.

v1

Offset pagination (page=1, page=2, …)

v2

Cursor pagination (opaque next cursor)

Impact

Efficient on large lists, but breaks any code that jumped to page N or computed a total page count.

v1

Ad hoc error messages per endpoint

v2

Structured errors with consistent codes

Impact

Your old error handling may not recognise the new shapes. Mandatory review.

v1

Mostly individual operations

v2

Bulk operations for invoices (approve, cancel, delete in batches)

Impact

Clear win for large loads — but watch idempotency on partial retries.

v1

Basic inventory

v2

Multi-warehouse with stock levels, in-transit stock and full warehouse CRUD

Impact

Cases that needed external logic in v1 are now a single native endpoint.

v1

No standard protocol for AI agents

v2

MCP (Model Context Protocol) server announced as coming soon

Impact

Your assistant can read and act on Holded without bespoke REST wrappers.

Public proof of coverage

We covered the entire v2 API and open-sourced it

We maintain an n8n community node for Holded with 100% coverage of API v2 — 42 resources · 323 operations. It is published on npm with signed provenance attestation from GitHub Actions, no manual tokens. If you want to automate against Holded without writing a full integration, it is free to start and needs no consulting.

When your case is more demanding than an n8n workflow — high volume, idempotency under concurrency, tax logic, SLAs — we build custom integrations directly against the v2 API. The node is a strong starting point and, sometimes, the whole solution.

How we build it

Production integrations, with a parallel period

An API integration that writes data cannot be flipped over in one shot. What we do on every project:

  • Full inventory of the v1 endpoints your current integration touches
  • Endpoint-by-endpoint mapping to the v2 equivalent, with change notes
  • Pagination rewrite: offset loops → cursor loops, with tests
  • Error handling rewrite for the new structured codes
  • Staging that receives the same traffic as production for 1–2 weeks
  • Output-equality validation, v1 vs v2, before cut-over
  • A documented rollback plan in case anything looks wrong after cut-over
FAQ

Holded API v2 — developer FAQ

How do I authenticate against the Holded API v2?

Holded uses a per-account API key sent as a request header on every call. You generate the key from Holded (Settings → Developers → API key) and pass it in the key header. There is no OAuth handshake for server-to-server integrations, so treat the key like a password: store it in a secret manager, never ship it to the browser, and rotate it if it leaks. Each key inherits the permissions of the account it belongs to.

What changed between API v1 and v2?

Three structural changes affect existing code. First, a single consolidated base URL with sections instead of several product-specific APIs. Second, cursor pagination (an opaque next cursor) instead of numbered offset pages, which is far more efficient on large lists but breaks any loop that assumed page numbers. Third, structured error responses with consistent codes instead of ad hoc per-endpoint messages. v2 also adds bulk operations, multi-warehouse inventory with in-transit stock, recurring invoices with a queryable calendar and native attachments.

How does pagination work in v2?

List endpoints return an opaque next cursor rather than a page number. You request the first page, read the cursor from the response, and pass it back on the next call until no cursor is returned. This is stable under concurrent writes and cheap on large datasets, but it means you cannot jump to page N or compute a total page count up front. If you are porting from v1, rewrite offset loops as cursor loops and add a test that walks a full multi-page result.

Are there webhooks in v2?

Holded documents webhooks as coming soon. Until they ship, robust integrations rely on cursor-based polling (much cheaper than v1 offset polling) or on triggers from the source system (Shopify, Stripe, and so on) that feed a persisted queue. When native webhooks arrive, you migrate one component at a time from polling to webhook without touching the rest of the flow.

What is the Holded MCP server that is announced as coming soon?

MCP is the Model Context Protocol, an open standard from Anthropic that lets AI agents access external systems through typed tools with controlled permissions. A native Holded MCP server means any connected assistant (Claude, or ChatGPT via adapters, or a custom agent) can read invoices, products or ledger entries without you writing a REST wrapper per use case. If you are planning an AI assistant on top of Holded, it is usually worth waiting for the native MCP instead of building plumbing that will be obsolete.

What are the rate limits and how should I handle errors?

Holded throttles per API key, so design for retries from day one. Respect 429 responses with exponential backoff, batch reads with the largest page size the endpoint allows, and cache reference data (products, contacts, tax rates) that does not change every minute. Because v2 returns structured errors with consistent codes, you can branch on the code rather than parsing free-text messages, which makes retry and idempotency logic much cleaner.

Can you build or migrate our Holded v2 integration?

Yes. We build new integrations directly on v2 and migrate existing v1 integrations with a parallel period: your v1 flow keeps producing while the v2 flow writes to staging until both reconcile. Scope and a fixed price come after a free 30-minute diagnostic where we map exactly which endpoints you touch, whether your integration writes (higher risk) or only reads, and where idempotency needs attention.

Building on the Holded API v2?

In 30 minutes we map your endpoints, flag the real risks — pagination, idempotency, rate limits — and tell you whether to build new or migrate.