Visió general
L'API té dues adreces. La de comptes, accounts.tributs.ad, et diu a quines empreses tens accés. Cada empresa serveix les seves dades a la seva pròpia adreça, i aquestes dades només passen per allà.
Qualsevol usuari pot crear un token, sigui quin sigui el seu rol. Si treballes en una gestoria, un sol token llegeix totes les empreses dels teus clients.
| URL base | Per a |
|---|---|
https://accounts.tributs.ad/api/v1 | Les empreses a les quals té accés el token |
https://{slug}.tributs.ad/api/v1 | Les dades d'una empresa |
Inici ràpid
-
Crea un token
A Tributs, obre el teu perfil → Connexions externes → Crear token. Posa-li el nom del programa que el farà servir i tria quan caduca: 30 dies, 90 dies o 1 any. El token (
trb_…) es mostra una sola vegada: copia'l en aquell moment. -
Troba les teves empreses
Cada empresa arriba amb el seu
api_base_url, que és on llegiràs les seves dades.cURLcurl https://accounts.tributs.ad/api/v1/companies \ -H "Authorization: Bearer $TRIBUTS_TOKEN"200 OK · application/json{ "data": [ { "id": "acme.tributs.ad", "name": "Acme Serveis SL", "display_name": "Acme", "role": "advisor", "status": "active", "api_base_url": "https://acme.tributs.ad/api/v1" } ], "next_cursor": null, "has_more": false } -
Llegeix dades
Les llistes es lliuren per pàgines. Aquest exemple porta totes les factures de venda des de l'1 de gener.
curl "https://acme.tributs.ad/api/v1/sales_invoices?date_from=2026-01-01&limit=200" \ -H "Authorization: Bearer $TRIBUTS_TOKEN"import os import requests BASE = "https://acme.tributs.ad/api/v1" HEADERS = {"Authorization": f"Bearer {os.environ['TRIBUTS_TOKEN']}"} params = {"date_from": "2026-01-01", "limit": 200} invoices = [] while True: response = requests.get(f"{BASE}/sales_invoices", headers=HEADERS, params=params, timeout=30) response.raise_for_status() page = response.json() invoices += page["data"] if not page["has_more"]: break params["cursor"] = page["next_cursor"]const BASE = "https://acme.tributs.ad/api/v1"; const headers = { Authorization: `Bearer ${process.env.TRIBUTS_TOKEN}` }; const invoices = []; let cursor; do { const url = new URL(`${BASE}/sales_invoices`); url.searchParams.set("date_from", "2026-01-01"); url.searchParams.set("limit", "200"); if (cursor) url.searchParams.set("cursor", cursor); const response = await fetch(url, { headers }); if (!response.ok) { const problem = await response.json().catch(() => ({})); throw new Error(problem.title ?? `HTTP ${response.status}`); } const page = await response.json(); invoices.push(...page.data); cursor = page.has_more ? page.next_cursor : undefined; } while (cursor);
Autenticació
Envia el token a la capçalera Authorization de cada petició, amb l'esquema Bearer. Totes les peticions van per HTTPS.
Authorization: Bearer trb_… - El token és opac:
trb_seguit de 40 caràcters. Tributs en guarda només una empremta (SHA-256), així que ningú el pot tornar a veure. - Caduca sempre: als 30 dies, als 90 dies o a l'any. T'escrivim 7 dies abans i el dia que caduca.
- Renovar genera una clau nova per al mateix token. L'anterior deixa de funcionar en menys d'un minut; el nom i l'historial es conserven.
- El pots revocar quan vulguis. La revocació arriba a totes les empreses en 60 segons com a màxim.
- Actua com tu: a cada empresa té exactament el teu rol i els teus permisos.
- Fins a 10 tokens actius per persona. Fes servir un token per a cada programa.
L'empresa té el control
El propietari de cada empresa veu a la configuració qui la consulta per API, amb quin token i quan, i pot tallar l'accés a tothom o a una persona concreta.
Paginació i sincronització
Les llistes retornen data, next_cursor i has_more. Mentre has_more sigui true, torna a cridar amb els mateixos paràmetres i cursor=<next_cursor>. limit va d'1 a 200 (50 per defecte, i 50 com a màxim amb expand=lines).
Els elements surten ordenats pel darrer canvi, del més antic al més recent. Per mantenir una còpia al dia, desa l'updated_at de l'últim element i passa'l com a updated_since la propera vegada: t'arriba el que ha canviat des de llavors. Desa els elements per id, substituint els que ja tens, perquè els de l'últim segon poden tornar a sortir.
Un document anul·lat torna a sortir amb status: "cancelled". Els esborranys no surten: només hi ha documents emesos. L'excepció són els moviments bancaris, que no s'emeten: surten sempre, i un de manual que s'elimini desapareix sense avís.
Les factures i els moviments bancaris accepten sort: total_desc (les factures de més import primer), issue_date_desc (les factures més recents primer) i date_desc (els moviments més recents primer). Un cursor només val per a l'ordre amb què es va demanar. Amb include=totals, la primera pàgina (la crida sense cursor) porta totals: quants elements compleixen els filtres i quant sumen, comptant totes les pàgines. Els anul·lats es compten a part i no sumen.
Recursos
Tots els recursos responen a GET. El contracte complet, amb cada camp i cada paràmetre, és el fitxer OpenAPI 3.1 que cada empresa serveix sense token a {api_base_url}/openapi.json. Importa'l a Postman o genera'n un client.
| Endpoint | Contingut | Filtres |
|---|---|---|
GET/companies | Empreses que pot llegir el token, amb l'api_base_url de cadascuna. Es crida a accounts.tributs.ad. | — |
GET/contacts | Clients i proveïdors, amb NRT, país i rols. | role |
GET/sales_invoices | Factures de venda emeses, abonaments i tancaments de caixa. expand=lines hi afegeix les línies i l'IGI per tipus. | date_fromdate_tostatustypecontact_idmin_totalsortinclude=totalsexpand=lines |
GET/purchase_invoices | Factures de compra i abonaments, amb l'IGI deduïble efectivament suportat. | date_fromdate_tostatustypecontact_idmin_totalsortinclude=totalsexpand=lines |
GET/journal_lines | Línies del llibre diari: data, compte, deure, haver, tercer i document d'origen. | date_fromdate_toaccountcontact_iddocument_id |
GET/accounts | Pla de comptes (PGC d'Andorra), amb número, nom i compte pare. | — |
GET/bank_transactions | Moviments bancaris i el seu estat de conciliació. | date_fromdate_tostatusbank_account_idmin_amountsortinclude=totals |
GET/bank_accounts | Comptes bancaris de l'empresa amb dos saldos: el dels llibres (ledger_balance) i el de l'extracte del banc (statement_balance). | date |
GET/receivables | El que deu cada client a dia d'avui: pendent, vençut, a 30 dies i bestretes sense aplicar. Per defecte, el saldo més gran primer; sort=oldest_due, el venciment més antic. | min_amountsortinclude=totals |
GET/payables | El que es deu a cada proveïdor, amb els mateixos camps que receivables. | min_amountsortinclude=totals |
GET/obligations | Calendari fiscal: model, període, termini, estat i el resultat de la declaració desada. GET /obligations/{id} hi afegeix les xifres casella per casella. | yearstatusdeadline_fromdeadline_to |
GET/payroll_summary | Totals de nòmines per mes: nòmines i persones, brut, net, CASS del treballador i de l'empresa, retencions (IRPF i IRNR) i cost total, amb assalariats i socis per separat. Sense noms. | month_frommonth_to |
GET/payslips | Nòmines, una per persona i mes: brut, net, CASS, retenció amb el seu tipus, cost d'empresa, estat i data de pagament. include=totals hi afegeix les sumes. | month_frommonth_toemployee_idstatuskindsortinclude=totals |
GET/employees | Persones de la plantilla: nom, alta i baixa, tipus de contracte, categoria i residència fiscal. | statuskind |
GET/reports/profit_and_loss | Compte de pèrdues i guanys per epígrafs, amb el detall per compte. | date_fromdate_toperiodicityperiods |
GET/reports/balance_sheet | Balanç per epígrafs, amb el detall per compte. | dateperiodicityperiods |
GET/reports/trial_balance | Balanç de sumes i saldos: saldo inicial, deure, haver i saldo final per compte. | date_fromdate_to |
Les llistes paginades (tots els recursos excepte companies, bank_accounts, payroll_summary i els informes) accepten també limit i cursor, i updated_since excepte receivables i payables, que són saldos a dia d'avui.
Per llegir un sol document: GET /sales_invoices/{id}, /purchase_invoices/{id}, /contacts/{id} i /obligations/{id} (per id o per code, com ara M900-T2-2026). Les factures hi arriben sempre amb les línies, i l'obligació amb les xifres de la declaració desada (filing): resultat i desglossament per casella dels models 900, 910, 800, 805, 810, 700, 710, 310 i 311. Les retencions surten en totals, sense la relació de perceptors.
Fora de la v1: PDF i adjunts, pressupostos, albarans, subscripcions i projectes. De les persones de la plantilla no surten mai el NRT, el número d'afiliació a la CASS, l'IBAN ni la data de naixement.
Exemple de resposta
{
"data": [
{
"id": "FV-26-00042",
"number": "FV-26-00042",
"type": "invoice",
"status": "unpaid",
"issue_date": "2026-10-02",
"due_date": "2026-11-01",
"contact_id": "Grup Ferrer SL",
"contact_name": "Grup Ferrer SL",
"contact_tax_id": "L712345A",
"currency": "EUR",
"net_amount": 1200.0,
"tax_amount": 54.0,
"total": 1254.0,
"outstanding_amount": 1254.0,
"document_currency": "EUR",
"document_total": 1254.0,
"exchange_rate": 1.0,
"credited_invoice_id": null,
"project_ids": [],
"description": "Consultoria setembre",
"disbursements_amount": 0.0,
"created_at": "2026-10-02T08:14:03Z",
"updated_at": "2026-10-02T08:14:03Z"
}
],
"next_cursor": "WyIyMDI2LTEwLTAyIDEwOjE0OjAzIiwiRlYtMjYtMDAwNDIiXQ",
"has_more": true
} Convencions
- JSON, amb noms de camp en anglès i en
snake_case. - Els estats són codis estables (
paid,unpaid,cancelled…) i no es tradueixen. - Les dates comptables van en format
YYYY-MM-DD(calendari d'Andorra). Els moments, en RFC 3339 i UTC. - Els imports són números amb 2 decimals en EUR, la moneda dels llibres. Els documents en moneda estrangera porten també
document_currency,document_totaliexchange_rate. - Els epígrafs dels informes s'identifiquen pel seu
code(Decret 479/2025). El text és l'oficial en català. - Les xifres d'un model tributari s'identifiquen pel número de casella (
box); l'etiqueta és en català, la llengua del formulari oficial.
Límits
60 peticions per minut per token i empresa, amb ràfegues de fins a 20. Un informe compta com 5, igual que bank_accounts, receivables, payables i payroll_summary. Com que el límit és per empresa, una gestoria pot llegir moltes empreses alhora; a més, cada adreça IP té un sostre global de 600 peticions per minut.
| Capçalera | Significat |
|---|---|
RateLimit-Limit | Peticions per minut: 60. |
RateLimit-Remaining | Peticions que encara pots fer ara mateix. |
RateLimit-Reset | Segons fins que el comptador es recupera del tot. |
RateLimit-Policy | La política aplicada: 60;w=60;burst=20. |
Retry-After | Amb 429 i 503: segons que cal esperar abans de tornar-ho a provar. |
Errors
Els errors segueixen l'RFC 9457 (application/problem+json). El camp code és estable i type enllaça amb la fila corresponent d'aquesta taula.
HTTP/1.1 401 Unauthorized
Content-Type: application/problem+json
{
"type": "https://tributs.ad/developers#errors-expired-token",
"title": "Access token expired",
"status": 401,
"code": "expired_token",
"instance": "/api/v1/sales_invoices"
} | Estat | code | Què cal fer |
|---|---|---|
| 401 | missing_token | Afegeix la capçalera Authorization: Bearer trb_…. |
| 401 | invalid_token | El token no existeix o està mal copiat. Revisa'l o crea'n un de nou. |
| 401 | expired_token | El token ha caducat. Crea'n un de nou des del teu perfil. |
| 401 | revoked_token | El token està revocat. Crea'n un de nou des del teu perfil. |
| 403 | no_access | No tens accés a aquesta empresa. |
| 403 | permission_denied | El teu rol en aquesta empresa no permet llegir aquest recurs. |
| 403 | api_access_disabled | El propietari ha tallat l'accés per API a l'empresa. |
| 403 | api_access_blocked | El propietari t'ha tallat l'accés per API a aquesta empresa. |
| 403 | company_suspended | La subscripció de l'empresa no està activa. |
| 400 | invalid_parameter | Un paràmetre no és vàlid. El camp detail diu quin. |
| 404 | not_found | El recurs o el document no existeix. |
| 405 | method_not_allowed | L'API només admet GET. |
| 429 | rate_limited | Espera els segons que indica Retry-After. |
| 500 | internal_error | Error per part nostra. Torna-ho a provar; si es repeteix, escriu-nos. |
| 503 | maintenance | L'empresa està en manteniment. Torna-ho a provar passats els segons de Retry-After. |
| 503 | auth_unavailable | No hem pogut comprovar el token. Torna-ho a provar en uns segons. |
Excel i Power BI
A Excel o a Power BI, crea primer un paràmetre de text TributsToken amb el token (Administra els paràmetres). Després obre Obtén dades → Consulta en blanc → Editor avançat i enganxa aquesta consulta, que recorre totes les pàgines.
let
Token = TributsToken,
Base = "https://acme.tributs.ad/api/v1/sales_invoices",
GetPage = (cursor as nullable text) =>
Json.Document(Web.Contents(Base, [
Query = if cursor = null
then [limit = "200"]
else [limit = "200", cursor = cursor],
Headers = [Authorization = "Bearer " & Token]
])),
Pages = List.Generate(
() => GetPage(null),
each _ <> null,
each if _[has_more] then GetPage(_[next_cursor]) else null
),
Rows = List.Combine(List.Transform(Pages, each _[data])),
Invoices = Table.FromRecords(Rows)
in
Invoices Si et demana credencials, tria Anònim: el token ja viatja a la capçalera. L'URL base fixa i els paràmetres a Query permeten actualitzar l'informe des del servei de Power BI; allà, a les credencials de l'origen de dades, marca «Skip test connection» (omet la prova de connexió), perquè aquesta prova es fa sense token i rep un error 401. El token queda desat dins del fitxer: fes-ne servir un només per a aquest informe i comparteix el fitxer només amb qui pot veure aquestes dades.
Assistents d'IA
Un assistent d'IA (ChatGPT, Claude i altres programes compatibles amb MCP) pot llegir les mateixes dades que aquesta API, amb les mateixes consultes i els teus permisos. No cal cap token: entres amb el teu usuari de Tributs.
- A l'assistent, afegeix un connector personalitzat amb l'adreça
https://mcp.tributs.ad/mcp, amb el/mcpdel final. - S'obre una pantalla de Tributs: entra amb el teu usuari i prem Permetre.
- A Ajustos → Perfil → Connexions externes veus l'aplicació connectada i li pots retirar el permís.
- Només lectura. Cada recurs d'aquesta pàgina és una consulta de l'assistent, i els que s'hi afegeixin li arriben sols.
- Límit propi: 120 peticions per minut per connexió, amb ràfegues de fins a 40, a més del límit de l'API per empresa.
- Claude Code, Cursor o un programa propi que parli MCP també poden entrar amb un token: envia'l com a
Authorization: Bearer trb_…a la mateixa adreça. - El que l'assistent llegeix passa pel proveïdor que tu has triat, amb les seves condicions.
Seguretat
Com protegim l'accés:
- Només lectura: cap endpoint de l'API modifica dades.
- Tributs només guarda una empremta del token (SHA-256).
- Caducitat obligatòria, i revocació i renovació des del perfil.
- Cada empresa veu qui la llegeix, i el propietari pot tallar l'accés.
- Límits per token i empresa, i HTTPS a totes les peticions.
Bones pràctiques
- Desa el token en un gestor de secrets o en una variable d'entorn. Mantén-lo fora del codi, dels repositoris i de les aplicacions que s'executen al navegador.
- Crea un token per a cada programa, amb la caducitat més curta que et vagi bé.
- Envia'l sempre a la capçalera
Authorization: les URL queden als historials i als registres dels servidors. - Si creus que s'ha filtrat, revoca'l des del perfil i crea'n un de nou. El prefix
trb_facilita que els escàners de secrets el trobin.
Per informar d'una vulnerabilitat, escriu a security@tributs.ad.
Versions
La versió va a l'URL (/api/v1/). La v1 només guanya camps: un canvi incompatible va a la v2.