Présentation
L'API a deux adresses. Celle des comptes, accounts.tributs.ad, indique à quelles entreprises vous avez accès. Chaque entreprise sert ses données à sa propre adresse, et ces données ne passent que par là.
Tout utilisateur peut créer un jeton, quel que soit son rôle. Dans un cabinet comptable, un seul jeton lit toutes les entreprises de vos clients.
| URL de base | Pour |
|---|---|
https://accounts.tributs.ad/api/v1 | Les entreprises auxquelles le jeton a accès |
https://{slug}.tributs.ad/api/v1 | Les données d'une entreprise |
Démarrage rapide
-
Créez un jeton
Dans Tributs, ouvrez votre profil → Connexions externes → Créer un jeton. Donnez-lui le nom du programme qui l'utilisera et choisissez quand il expire : 30 jours, 90 jours ou 1 an. Le jeton (
trb_…) ne s'affiche qu'une fois : copiez-le à ce moment-là. -
Trouvez vos entreprises
Chaque entreprise arrive avec son
api_base_url, l'adresse où vous lirez ses données.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 } -
Lisez les données
Les listes sont paginées. Cet exemple récupère toutes les factures de vente depuis le 1er janvier.
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);
Authentification
Envoyez le jeton dans l'en-tête Authorization de chaque requête, avec le schéma Bearer. Toutes les requêtes passent par HTTPS.
Authorization: Bearer trb_… - Le jeton est opaque :
trb_suivi de 40 caractères. Tributs n'en conserve qu'une empreinte (SHA-256) : personne ne peut le revoir. - Il expire toujours : après 30 jours, 90 jours ou 1 an. Nous vous écrivons 7 jours avant et le jour de l'expiration.
- Renouveler crée une nouvelle clé pour le même jeton. L'ancienne cesse de fonctionner en moins d'une minute ; le nom et l'historique sont conservés.
- Vous pouvez le révoquer à tout moment. La révocation atteint toutes les entreprises en 60 secondes au plus.
- Il agit en votre nom : dans chaque entreprise, il a exactement votre rôle et vos autorisations.
- Jusqu'à 10 jetons actifs par personne. Utilisez un jeton par programme.
L'entreprise garde le contrôle
Le propriétaire de chaque entreprise voit dans les réglages qui la consulte par l'API, avec quel jeton et quand, et peut couper l'accès à tous ou à une personne.
Pagination et synchronisation
Les listes renvoient data, next_cursor et has_more. Tant que has_more vaut true, rappelez avec les mêmes paramètres et cursor=<next_cursor>. limit va de 1 à 200 (50 par défaut, et 50 au maximum avec expand=lines).
Les éléments sont triés par dernière modification, du plus ancien au plus récent. Pour garder une copie à jour, conservez le updated_at du dernier élément et passez-le en updated_since la fois suivante : vous recevez ce qui a changé depuis. Enregistrez les éléments par id en remplaçant ceux que vous avez déjà, car ceux de la dernière seconde peuvent revenir.
Un document annulé réapparaît avec status: "cancelled". Les brouillons n'apparaissent pas : seuls les documents émis sont renvoyés. Les mouvements bancaires font exception, car ils ne sont pas émis : ils apparaissent toujours, et un mouvement manuel supprimé disparaît sans préavis.
Les factures et les mouvements bancaires acceptent sort : total_desc (les factures les plus élevées d'abord), issue_date_desc (les factures les plus récentes d'abord) et date_desc (les mouvements les plus récents d'abord). Un cursor ne vaut que pour le tri avec lequel il a été demandé. Avec include=totals, la première page (l'appel sans cursor) contient totals : combien d'éléments correspondent aux filtres et quelle somme ils représentent, toutes pages confondues. Les éléments annulés sont comptés à part et n'entrent pas dans les sommes.
Ressources
Toutes les ressources répondent à GET. Le contrat complet, avec chaque champ et chaque paramètre, est le fichier OpenAPI 3.1 que chaque entreprise sert sans jeton à {api_base_url}/openapi.json. Importez-le dans Postman ou générez-en un client.
| Endpoint | Contenu | Filtres |
|---|---|---|
GET/companies | Entreprises que le jeton peut lire, avec l'api_base_url de chacune. S'appelle sur accounts.tributs.ad. | — |
GET/contacts | Clients et fournisseurs, avec NRT, pays et rôles. | role |
GET/sales_invoices | Factures de vente émises, avoirs et clôtures de caisse. expand=lines ajoute les lignes et l'IGI par taux. | date_fromdate_tostatustypecontact_idmin_totalsortinclude=totalsexpand=lines |
GET/purchase_invoices | Factures d'achat et avoirs, avec l'IGI déductible effectivement supporté. | date_fromdate_tostatustypecontact_idmin_totalsortinclude=totalsexpand=lines |
GET/journal_lines | Lignes du journal : date, compte, débit, crédit, tiers et document d'origine. | date_fromdate_toaccountcontact_iddocument_id |
GET/accounts | Plan comptable (PGC d'Andorre), avec numéro, nom et compte parent. | — |
GET/bank_transactions | Mouvements bancaires et leur état de rapprochement. | date_fromdate_tostatusbank_account_idmin_amountsortinclude=totals |
GET/bank_accounts | Comptes bancaires de l'entreprise avec deux soldes : celui des livres (ledger_balance) et celui du relevé de la banque (statement_balance). | date |
GET/receivables | Ce que doit chaque client à ce jour : montant ouvert, échu, à 30 jours et acomptes non imputés. Par défaut, le solde le plus élevé d'abord ; sort=oldest_due, l'échéance la plus ancienne. | min_amountsortinclude=totals |
GET/payables | Ce qui est dû à chaque fournisseur, avec les mêmes champs que receivables. | min_amountsortinclude=totals |
GET/obligations | Calendrier fiscal : modèle, période, échéance, statut et résultat de la déclaration enregistrée. GET /obligations/{id} ajoute les chiffres case par case. | yearstatusdeadline_fromdeadline_to |
GET/payroll_summary | Totaux de paie par mois : bulletins et personnes, brut, net, CASS du salarié et de l'entreprise, retenues (IRPF et IRNR) et coût total, salariés et associés séparés. Sans noms. | month_frommonth_to |
GET/payslips | Bulletins de paie, un par personne et par mois : brut, net, CASS, retenue avec son taux, coût pour l'entreprise, état et date de paiement. include=totals ajoute les sommes. | month_frommonth_toemployee_idstatuskindsortinclude=totals |
GET/employees | Personnes de l'effectif : nom, dates d'entrée et de sortie, type de contrat, catégorie et résidence fiscale. | statuskind |
GET/reports/profit_and_loss | Compte de résultat par rubrique, avec le détail par compte. | date_fromdate_toperiodicityperiods |
GET/reports/balance_sheet | Bilan par rubrique, avec le détail par compte. | dateperiodicityperiods |
GET/reports/trial_balance | Balance générale : solde d'ouverture, débit, crédit et solde de clôture par compte. | date_fromdate_to |
Les listes paginées (toutes les ressources sauf companies, bank_accounts, payroll_summary et les états) acceptent aussi limit et cursor, ainsi que updated_since sauf receivables et payables, qui sont des soldes à ce jour.
Pour lire un seul document : GET /sales_invoices/{id}, /purchase_invoices/{id}, /contacts/{id} et /obligations/{id} (par id ou par code, par exemple M900-T2-2026). Les factures arrivent toujours avec leurs lignes, et l'obligation avec les chiffres de la déclaration enregistrée (filing) : résultat et détail par case des formulaires 900, 910, 800, 805, 810, 700, 710, 310 et 311. Les retenues sortent en totaux, sans la liste des bénéficiaires.
Hors de la v1 : PDF et pièces jointes, devis, bons de livraison, abonnements et projets. Pour les personnes de l'effectif, le NRT, le numéro d'affiliation à la CASS, l'IBAN et la date de naissance ne sont jamais renvoyés.
Exemple de réponse
{
"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
} Conventions
- JSON, avec des noms de champ en anglais et en
snake_case. - Les statuts sont des codes stables (
paid,unpaid,cancelled…) et ne sont jamais traduits. - Les dates comptables sont au format
YYYY-MM-DD(calendrier d'Andorre). Les instants, en RFC 3339 et UTC. - Les montants sont des nombres à 2 décimales en EUR, la devise de la comptabilité. Les documents en devise étrangère portent aussi
document_currency,document_totaletexchange_rate. - Les rubriques des états s'identifient par leur
code(Decret 479/2025). Le libellé est le texte officiel en catalan. - Les chiffres d'un formulaire fiscal s'identifient par leur numéro de case (
box) ; le libellé est en catalan, la langue du formulaire officiel.
Limites
60 requêtes par minute par jeton et par entreprise, en rafales de 20 au plus. Un état compte pour 5, tout comme bank_accounts, receivables, payables et payroll_summary. La limite étant par entreprise, un cabinet peut lire de nombreuses entreprises en parallèle ; chaque adresse IP a en plus un plafond global de 600 requêtes par minute.
| En-tête | Signification |
|---|---|
RateLimit-Limit | Requêtes par minute : 60. |
RateLimit-Remaining | Requêtes que vous pouvez encore faire tout de suite. |
RateLimit-Reset | Secondes avant que le compteur soit de nouveau plein. |
RateLimit-Policy | La politique appliquée : 60;w=60;burst=20. |
Retry-After | Avec 429 et 503 : secondes à attendre avant de réessayer. |
Erreurs
Les erreurs suivent la RFC 9457 (application/problem+json). Le champ code est stable et type renvoie à la ligne correspondante de ce tableau.
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"
} | Statut | code | Que faire |
|---|---|---|
| 401 | missing_token | Ajoutez l'en-tête Authorization: Bearer trb_…. |
| 401 | invalid_token | Le jeton n'existe pas ou a été mal copié. Vérifiez-le ou créez-en un nouveau. |
| 401 | expired_token | Le jeton a expiré. Créez-en un nouveau depuis votre profil. |
| 401 | revoked_token | Le jeton a été révoqué. Créez-en un nouveau depuis votre profil. |
| 403 | no_access | Vous n'avez pas accès à cette entreprise. |
| 403 | permission_denied | Votre rôle dans cette entreprise ne permet pas de lire cette ressource. |
| 403 | api_access_disabled | Le propriétaire a coupé l'accès API de l'entreprise. |
| 403 | api_access_blocked | Le propriétaire vous a coupé l'accès API à cette entreprise. |
| 403 | company_suspended | L'abonnement de l'entreprise n'est pas actif. |
| 400 | invalid_parameter | Un paramètre n'est pas valide. Le champ detail indique lequel. |
| 404 | not_found | La ressource ou le document n'existe pas. |
| 405 | method_not_allowed | L'API n'accepte que GET. |
| 429 | rate_limited | Attendez le nombre de secondes indiqué dans Retry-After. |
| 500 | internal_error | Erreur de notre côté. Réessayez ; si elle persiste, écrivez-nous. |
| 503 | maintenance | L'entreprise est en maintenance. Réessayez après les secondes de Retry-After. |
| 503 | auth_unavailable | Nous n'avons pas pu vérifier le jeton. Réessayez dans quelques secondes. |
Excel et Power BI
Dans Excel ou Power BI, créez d'abord un paramètre texte TributsToken contenant le jeton (Gérer les paramètres). Ouvrez ensuite Obtenir les données → Requête vide → Éditeur avancé et collez cette requête, qui parcourt toutes les pages.
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 des identifiants vous sont demandés, choisissez Anonyme : le jeton voyage déjà dans l'en-tête. L'URL de base fixe et les paramètres dans Query permettent d'actualiser le rapport depuis le service Power BI ; là, dans les identifiants de la source de données, cochez « Skip test connection » (ignorer le test de connexion), car ce test se fait sans jeton et reçoit une erreur 401. Le jeton est enregistré dans le fichier : utilisez-en un réservé à ce rapport et partagez le fichier uniquement avec les personnes autorisées à voir ces données.
Assistants IA
Un assistant IA (ChatGPT, Claude et d'autres logiciels compatibles MCP) peut lire les mêmes données que cette API, avec les mêmes requêtes et vos droits. Aucun jeton n'est nécessaire : vous vous connectez avec votre utilisateur Tributs.
- Dans l'assistant, ajoutez un connecteur personnalisé avec l'adresse
https://mcp.tributs.ad/mcp, avec le/mcpfinal. - Un écran de Tributs s'ouvre : connectez-vous avec votre utilisateur et cliquez sur Autoriser.
- Dans Réglages → Profil → Connexions externes, vous voyez l'application connectée et vous pouvez lui retirer l'autorisation.
- Lecture seule. Chaque ressource de cette page est une requête de l'assistant, et les nouvelles lui arrivent d'elles-mêmes.
- Limite propre : 120 requêtes par minute par connexion, avec des rafales jusqu'à 40, en plus de la limite de l'API par entreprise.
- Claude Code, Cursor ou un logiciel maison qui parle MCP peuvent aussi entrer avec un jeton : envoyez-le en
Authorization: Bearer trb_…à la même adresse. - Ce que l'assistant lit passe par le fournisseur que vous avez choisi, selon ses conditions.
Sécurité
Comment nous protégeons l'accès :
- Lecture seule : aucun endpoint de l'API ne modifie de données.
- Tributs ne conserve qu'une empreinte du jeton (SHA-256).
- Expiration obligatoire, révocation et renouvellement depuis le profil.
- Chaque entreprise voit qui la lit, et son propriétaire peut couper l'accès.
- Limites par jeton et par entreprise, et HTTPS pour chaque requête.
Bonnes pratiques
- Conservez le jeton dans un gestionnaire de secrets ou une variable d'environnement. Gardez-le hors du code, des dépôts et des applications qui s'exécutent dans le navigateur.
- Créez un jeton par programme, avec l'expiration la plus courte qui vous convient.
- Envoyez-le toujours dans l'en-tête
Authorization: les URL restent dans les historiques et les journaux des serveurs. - Si vous pensez qu'il a fuité, révoquez-le depuis votre profil et créez-en un nouveau. Le préfixe
trb_aide les scanners de secrets à le repérer.
Pour signaler une vulnérabilité, écrivez à security@tributs.ad.
Versions
La version figure dans l'URL (/api/v1/). La v1 ne fait qu'ajouter des champs : un changement incompatible passe en v2.