| name | holded |
| description | Interact with the Holded API (v2) via the pyholded library and its `holded` CLI — invoices and other sales/purchase documents, contacts, products, services, CRM funnels/leads, projects, tasks, employees. Use when the user wants to create or query anything in Holded. Triggers — "Holded", "create an invoice", "list contacts/clients", "credit note", "estimate/quote", "sales order", "CRM funnel/lead", "download invoice PDF", "send invoice by email", "list employees". |
| license | MIT |
Holded (API v2 via pyholded)
Holded is a Spanish business-management ERP. This skill drives its v2 REST API
through pyholded — a typed Python client +
holded CLI generated from a declarative resource registry. Prefer it over raw
HTTP: it handles auth, cursor pagination, output formats, and errors.
Setup (once)
-
Token — the user generates a Personal Access Token in Holded:
Settings → Developers → Credentials → Add API Token (it starts with pat_).
Export it (never hardcode or commit it):
export HOLDED_TOKEN="pat_xxxxxxxx_yyyyyyyy"
Resolution order: --token flag → HOLDED_TOKEN / HOLDED_API_KEY env →
~/.config/pyholded/config.toml. Multiple accounts: HOLDED_TOKEN_<NAME> env
or config tables, selected with --account <name>.
-
Install — needs Python 3.14+. Use a venv:
python3 -m venv .venv && .venv/bin/pip install pyholded
This installs the holded CLI (.venv/bin/holded) and the pyholded package.
If the token is missing/invalid you get an AuthenticationError (Python) or an
auth error from the CLI; a wrong token returns {"status":0,"info":"Invalid key"}.
Two ways to call it
A) CLI (preferred for one-off queries and in any harness)
holded [GLOBAL OPTS] <resource> <operation> [OPTS]
- Global:
--token, -a/--account <name>, --all-accounts, --config FILE,
--base-url, -o/--output rich|json|toon (default rich; use -o json
when you need to parse the result), --timeout.
- Operations:
list, get --id <id>, create --data '<json>' (or @file.json),
update --id <id> --data '<json>', delete --id <id>. Documents also have
get-pdf --id <id> and send --id <id>. Leads also have create-note /
create-task.
list options: --limit N, --cursor <c>, --page N, --all (follow the
cursor and merge every page).
holded -o json contacts list --limit 5
holded -o json contacts list --all
holded -o json invoices get --id 5f8d0a2b1c9e4a3f2b6d7c8e
holded invoices get-pdf --id 5f8d0a2b1c9e4a3f2b6d7c8e
holded contacts create --data '{"name":"ACME SL","type":"client"}'
holded resources
holded raw GET taxes --param limit=5
B) Python client (preferred for scripts / multi-step logic)
from pyholded import HoldedClient
with HoldedClient() as client:
page = client.invoices.list(params={"limit": 50})
everyone = client.contacts.list(paginate=True)
inv = client.invoices.get(id="5f8d0a2b1c9e4a3f2b6d7c8e")
new = client.contacts.create(data={"name": "ACME SL", "type": "client"})
pdf = client.invoices.getPdf(id="5f8d0a2b1c9e4a3f2b6d7c8e")
raw = client.request("GET", "taxes", params={"limit": 5})
Exceptions: HoldedError (base), AuthenticationError, NotFoundError,
RateLimitError, APIError, EndpointNotFoundError, ConfigError.
Multi-account: MultiClient.from_accounts().
Resources
All 27 resources live under one flat v2 namespace, across modules invoicing, crm,
projects, team:
- Documents (CRUD +
getPdf + send): invoices, credit_notes, sales_orders,
estimates, proformas, waybills, sales_receipts, purchases, purchase_orders
- Contacts: contacts, contact_groups
- Catalog & money: products, services, taxes·, warehouses, payment_methods·,
payments, sales_channels, expenses_accounts (· = read-only list/get)
- CRM: funnels, leads (+ createNote/createTask), events, bookings·,
booking_locations·
- Projects/Team: projects, tasks, employees
Discover at runtime — don't trust hardcoded tables:
holded resources → authoritative operation set per resource.
holded -o json <resource> get --id <id> → the live field shape.
References (load on demand)
reference/api-overview.md — auth, pagination, calling syntax, output, errors,
what's NOT in v2. Read once per session.
reference/documents.md — document + line shape for creating invoices etc.
reference/resources.md — enums, relationships, read-only flags, PII handling —
the judgment that holded resources / get don't give you.
Operating rules
- Confirm before writes. create/update/delete/send make real, often
fiscally-binding records (invoices, credit notes). Show the user the exact
resource, operation, and JSON body, and get explicit go-ahead. list/get are safe.
- Never print or commit the token. It is read from env/config only.
- IDs are 24-hex MongoDB ObjectIds (e.g.
5eaa9a4e6a972867eb037cd7), returned
as id. Capture them to chain calls.
- Pagination is cursor-based. Responses are
{items, cursor, has_more}. Don't
hand-roll cursor loops — use --all (CLI) or paginate=True (Python).
- Fields are
snake_case (e.g. contact_id, document_number, due_date).
- Parse with
-o json — the default rich output is for humans, not parsing.
- On
RateLimitError / HTTP 429, back off and retry.
Notes