I build integrations on top of Holded, the invoicing and accounting platform a lot of Spanish SMEs run on. For most of the last year, every Holded integration I shipped had the same shape: poll the API on a schedule, diff the results, push changes somewhere else.
That changed this year. Holded's API v2 now has signed webhooks, and in August Holded shipped an official MCP server so Claude or ChatGPT can talk to your account. Both are good news. Both also come with details that will bite you if you only read the announcement. Here is what I have learned wiring them into real projects.
1. Webhooks exist now, but not for everything
Holded sends webhooks when a contact, invoice or payment is created, updated or deleted. Each delivery is signed with HMAC, so you can verify it came from Holded, and it carries an x-holded-webhook-id header.
Use that header. A webhook can arrive more than once (retries after a timeout are normal), and "I processed this invoice twice" is the most expensive bug in accounting integrations. My rule: store the webhook id, refuse to process one you have already seen, and only then do the work.
What webhooks do not cover matters just as much. There is no event for an invoice falling due. If your flow is "remind the customer three days before the due date" or "escalate invoices 15 days overdue", you still need a scheduled job that queries pending invoices every day. Webhooks replace part of your polling, not all of it.
2. Polling has a monthly price tag
This is the one that surprised me. The Holded API has a monthly request quota that depends on the plan, and every API key on the account shares it. At the time of writing, the documented quotas are 500 requests a month on Plus, 2,000 on Basic, 7,500 on Standard and 30,000 on Advanced.
Now do the maths on a naive integration that polls every 5 minutes: 12 calls an hour, 288 a day, about 8,640 a month. One modest polling loop is already over the Standard quota, before you count the calls that actually do something.
So the design order for a Holded integration in 2026 is:
- Use webhooks for everything they cover.
- Poll only what has no event, and as rarely as the business allows (a daily due-date check, not a 5-minute one).
- Count your calls per month before you go live, against the customer's plan.
3. An update replaces the whole record
In API v2, a PUT on a contact or an invoice replaces all its editable fields. If you send only the field you want to change, you wipe the rest.
This shows up the moment you sync data back into Holded, for example marking a contact as unsubscribed after it opted out in your email tool. The safe pattern is read, merge, write the full object. Boring, but it is the difference between "we flagged the unsubscribe" and "we deleted the customer's address".
4. The MCP server is real, and it is deliberately limited
In August 2026 Holded published an official MCP server. You add it as a custom connector in Claude (and it also works in ChatGPT), authorise it with your Holded user, and choose between two profiles:
- Analytics: read only. Good for "how much are we owed?" or "what did we invoice this quarter?".
- Operational: can create contacts, CRM items, quotes, projects and inventory records. Accounting, invoices and taxes stay read only even here.
I think that last restriction is exactly right. An issued invoice in Spain is not something you edit, you correct it with a corrective invoice, and with Verifactu that discipline is not optional. The raw API is a different story: a key with write permission on invoices can create, replace and delete them, including deleting up to 100 in a single call. If you build your own MCP server on the API, do not expose that. Scope the key per resource (read on invoices, write only on drafts), drop the delete tools entirely, and validate every amount against Holded before anything uses it.
For a lot of small companies, the official connector in the analytics profile is all they need, and you do not need to build anything. Custom work starts to make sense when you want processes that run without anyone in the chat, validation against the company's own rules, or an audit log of every call. I wrote up where that line sits here (in Spanish).
5. No-code users get some of this for free
If you use n8n, the verified Holded node I maintain covers the whole API v2 plus a webhook trigger, so you can start flows from Holded events instead of a schedule. The quota point above still applies inside n8n: a Schedule trigger every 5 minutes burns the same 8,640 calls a month.
The short version
- Webhooks for contacts, invoices and payments: use them, and deduplicate by webhook id.
- No due-date event: keep one daily scheduled check.
- Count your API calls per month against the customer's plan before launch.
-
PUTreplaces the whole record: read, merge, write. - The official MCP server keeps invoices read only. Keep that rule in anything you build.
If you are migrating an older integration, I also keep a list of traps when moving from Holded API v1 to v2.
I build these integrations at Francodesystems. Happy to answer questions in the comments.
Top comments (0)