API REST et serveur MCP

Pilotez votre comptabilité depuis un autre logiciel : une boutique en ligne qui enregistre chaque vente, un agent IA qui saisit les opérations, un outil de reporting qui lit le bilan. Tout ce que fait l'application est accessible, avec les mêmes contrôles comptables.

API REST : https://votre-site/api/v1
Serveur MCP : https://votre-site/mcp

Démarrer en trois étapes

1

Créez une clé

Dans l'application : menu API et intégrations → Créer une clé. Copiez-la : elle ne s'affiche qu'une fois.

2

Faites un premier appel

Lisez les informations de la société avec la clé dans l'en-tête Authorization.

3

Ou branchez un agent

Donnez l'adresse /mcp et la clé à Claude, Cursor ou votre agent : il découvre seul les outils.

curl https://votre-site/api/v1/societe \
  -H "Authorization: Bearer clt_VOTRE_CLE"

Clés et droits

Une clé donne accès à une seule société. Elle se transmet à chaque requête dans l'en-tête Authorization: Bearer clt_…. Seul l'administrateur de la société peut en créer (20 au plus) ou en révoquer ; la révocation est immédiate. ComptaLT ne conserve qu'une empreinte de la clé : perdue, elle ne peut pas être retrouvée, il faut en créer une nouvelle.

DroitsPermet
Lecture seuleToutes les requêtes GET : écritures, rapports, factures, clients, stock, commandes, fournisseurs, banque, exports PDF.
Lecture et écritureEn plus, des modifications, selon la portée choisie à la création de la clé.

Portée d'une clé d'écriture

Une clé d'écriture reçoit une portée à sa création (champ portee de POST /api/cles-api, écran Réglages > API et intégrations). Donnez à chaque logiciel la plus étroite qui lui suffit : une clé collée dans une boutique est stockée en clair dans la base de la boutique.

PortéePermet
boutiqueCe qu'appellent les modules PrestaShop et WooCommerce : GET /societe, /canaux, /commandes (et leurs paiements, remboursements, annulations), /paiements, articles (PUT /stock/articles/reference/{reference}, POST /stock/articles/lot, lectures de /stock). Rien d'autre, pas même la lecture des écritures.
integrations (par défaut)Toutes les lectures, ce que permet boutique, et ce qu'appellent n8n, Zapier et Make et les caisses enregistreuses : POST /ecritures, POST /factures et /factures/{id}/emettre, /encaisser, /envoyer, POST /clients, POST /fournisseurs/factures et /fournisseurs/factures/{id}/payer, abonnements POST /webhooks, PUT et DELETE /webhooks/{id}, POST /caisse/clotures et /caisse/import.
completeToute l'API publique : réglages de la société (IBAN, raison sociale), exercices (création, clôture, réouverture, suppression), ouverture, plan comptable, banque, TVA, justificatifs, devis, contrats, suppressions, secret, essai et renvoi des webhooks. À cocher explicitement ; c'est la portée d'un agent IA (MCP) qui doit tout faire.
heriteeClé créée avant les portées (04.10.2026) : tout ce qu'elle permettait, outils MCP compris, sauf les réglages de la société, la suppression d'un exercice, le secret, l'essai et le renvoi des webhooks. L'administrateur peut la restreindre en un clic (PUT /api/cles-api/{id}/portee avec { "portee": "integrations" }).

Hors de sa portée, une clé reçoit 403 avec un message qui dit quelle portée demander. Un abonnement webhook créé avec une clé lui est lié (cleApiId, cleApiNom dans GET /webhooks) : quand la clé est révoquée, il est désactivé et ne reçoit plus rien. Quelle que soit sa portée, une clé ne modifie, n'essaie, ne renvoie ni ne supprime que les abonnements qu'elle a créés : ceux créés dans l'application ou par une autre clé lui répondent 403. Un abonnement désactivé ne se réactive par une clé que si c'est elle qui l'a désactivé (desactiveParCle) : désactivé dans l'application, ou à la révocation d'une clé, seule l'application le réactive. Un déclencheur n8n, Zapier ou Make abonné avant ce lien (champ source, sans cleApiId) peut encore être supprimé, désactivé ou réactivé à l'identique par une clé (adresse, événements et description inchangés), jamais modifié ni lié à elle. Le cycle des modules n'utilise que cela : abonnement (POST) et désabonnement (DELETE) de Zapier et Make, création, réactivation et suppression de ses propres abonnements par n8n.

Aucune clé ne donne accès aux utilisateurs, aux mots de passe, à la double authentification ni aux clés elles-mêmes. Le remplacement complet d'une comptabilité (import d'une sauvegarde) reste réservé à l'application, et à l'administrateur de la société ; chaque restauration est inscrite dans un journal d'audit à part, que la restauration ne remplace pas. Depuis le 04.10.2026, les comptabilités sont au format de données 6 (bornes des exercices, périodes TVA déclarées, historique des clôtures et réouvertures) : une sauvegarde à ce format est refusée (409) par un serveur ComptaLT plus ancien. Une clé est révoquée automatiquement si l'utilisateur qui l'a créée est supprimé.

Routes ouvertes à une clé

Une clé n'ouvre que les ressources documentées ici (liste blanche) : /societe, /settings, /comptes, /exercices, /ouverture, /ecritures, /pieces, /rapports, /tva, /exports, /factures, /clients, /devis, /opportunites, /contrats, /stock, /canaux, /commandes, /paiements, /fournisseurs, /banque, /caisse et /webhooks, et ce qui est en dessous. Toute autre adresse répond 403 à une clé, même si l'application l'utilise : par exemple /etat (comptabilité entière), /connexions, /echanges/…, /exports/sauvegarde et /exports/ticket, ainsi que les utilisateurs et les clés. Le refus porte le message « Cette opération n'est pas disponible par clé API : elle reste réservée à l'application (voir /developpeurs). » ; une clé en lecture seule qui tente une modification reçoit « Cette clé API est en lecture seule. » Les règles s'appliquent à l'adresse décodée, comme la lit le serveur : /exports/sauvegard%65 est /exports/sauvegarde et reçoit le même refus.

Conventions

CodeSignification
200 / 201Succès.
400Corps de requête invalide : un champ n'a pas le bon type (texte, nombre, liste, objet). La réponse donne le détail de chaque champ refusé, voir ci-dessous.
401Clé absente, inconnue ou révoquée, ou société désactivée.
403Clé en lecture seule pour une modification, ou adresse non ouverte aux clés (liste blanche).
404Ressource introuvable, ou adresse mal écrite (casse comprise).
409La comptabilité a changé depuis la révision envoyée dans If-Match (corps { "erreur": "…", "code": "revision" }) : rien n'a été modifié, relisez puis recommencez. Code conflit : un autre conflit (traitement trop long, inscription simultanée) ; code version_future : données enregistrées par une version plus récente de ComptaLT.
413Corps ou fichier trop volumineux (pièce jointe : 20 Mo au plus).
422Refus comptable (toujours 422, quel que soit son code) : écriture déséquilibrée, exercice clôturé, compte inconnu, stock insuffisant, montant illisible, drapeau decompteTva mal posé, écriture verrouillée (exercice clôturé ou période TVA déclarée) modifiée ou supprimée, réouverture sans motif…
429Trop de requêtes avec des clés inconnues depuis votre adresse : attendez le nombre de secondes indiqué par Retry-After.
500Erreur interne (un défaut de ComptaLT) : { "erreur": "Erreur interne (référence K7M2Q9XA).", "code": "interne", "reference": "K7M2Q9XA" }. Le détail technique n'est jamais renvoyé : communiquez la référence au support.
503Service momentanément indisponible, en particulier trop d'exports en cours sur la plateforme : réessayez après le nombre de secondes indiqué par Retry-After. Sans Retry-After : l'export demande plus de mémoire que la limite d'un export sur ce serveur, un nouvel essai échouerait aussi (contactez le support).

Corps refusé : le détail des champs (400)

Avant tout traitement, le corps des requêtes /api/v1 (et donc des outils MCP) est contrôlé : seuls les types incohérents sont refusés, par exemple un libellé envoyé comme objet, une liste lignes qui n'est pas une liste ou un client qui n'est pas un objet. Les champs inconnus sont ignorés, un nombre en texte ("125.50") et un champ vide restent acceptés ; les contrôles comptables (équilibre, exercice, compte…) répondent toujours 422. Rien n'est enregistré ; la réponse donne le premier motif dans erreur et jusqu'à 20 motifs dans details, chacun avec le chemin du champ (lignes.0.compteNo : premier élément de lignes) :

# Réponse 400 à une écriture dont le libellé est un objet
{
  "erreur": "Requête invalide : libelle : texte attendu.",
  "code": "invalide",
  "details": [
    { "champ": "libelle", "message": "texte attendu" }
  ]
}

Codes d'erreur

Chaque réponse en erreur porte un champ code, stable d'une version à l'autre : testez le code, pas le message. Un refus de la comptabilité répond toujours 422 sur /api/v1 (et 200 avec { "res": { "ok": false, "message", "code" } } sur /api/compta), même quand son code est introuvable ou invalide : le statut HTTP des intégrations existantes ne change pas, le code précise la raison. Les autres erreurs ont le statut de leur code.

CodeStatutSignification
refus422Règle comptable ou métier : écriture déséquilibrée, exercice clôturé, stock insuffisant…
doublon_probable422Paiement déjà encaissé par le relevé bancaire, voir ci-dessous.
invalide400 (422 pour un refus de la comptabilité)Requête mal formée : champ manquant, type ou format incorrect.
non_authentifie401Clé absente, inconnue ou révoquée.
interdit403Clé en lecture seule, adresse non ouverte aux clés, société de démonstration.
introuvable404 (422 pour un refus de la comptabilité)Ressource ou adresse inexistante.
conflit409Traitement concurrent : recommencez.
revision409La comptabilité a changé depuis la révision envoyée dans If-Match.
version_future409Données enregistrées par une version plus récente de ComptaLT.
trop_volumineux413Corps ou fichier trop volumineux.
trop_de_requetes429Trop de requêtes : attendez Retry-After secondes.
indisponible503Service momentanément indisponible (exports, prestataire).
interne500Défaut de ComptaLT : communiquez la reference au support.

Renvoyer une requête sans risque de doublon

Ajoutez l'en-tête Idempotency-Key à toute modification (POST, PUT, DELETE), sur /api/v1/… comme sur /api/compta/…, avec une valeur propre à l'opération : le numéro de commande de votre boutique, un identifiant tiré au hasard. Si la même requête arrive à nouveau dans les 24 heures (coupure réseau, nouvel essai automatique), ComptaLT ne l'exécute pas une deuxième fois : il renvoie la réponse d'origine avec l'en-tête Idempotent-Replayed: true. Deux envois simultanés n'enregistrent qu'une opération : le second attend la fin du premier.

Ne pas écraser une modification faite entre-temps

Chaque réponse porte la révision de la comptabilité dans l'en-tête ComptaLT-Revision (un nombre qui augmente à chaque enregistrement). Elle est aussi dans l'ETag (fort, ETag: "12") : d'une lecture, la révision lue ; d'une modification, la révision qu'elle a enregistrée (une modification refusée ou qui n'enregistre rien n'a pas d'ETag). Pour une modification qui dépend de ce que vous avez lu, envoyez cette révision dans l'en-tête facultatif If-Match (If-Match: "12" ou If-Match: 12) : si la comptabilité a changé depuis (autre utilisateur, autre intégration), la requête est refusée en 409 sans rien modifier ; relisez, puis refaites la modification. Sans If-Match (ou avec If-Match: *), rien ne change : la modification s'applique à la comptabilité du moment.

L'ETag d'une lecture se renvoie tel quel en If-Match. Les réponses de l'API ne sont pas gardées en cache (Cache-Control: no-store). Avant le 04.10.2026, l'ETag d'une lecture était une empreinte du contenu (W/"…"), toujours refusée en If-Match : prenez la révision dans ComptaLT-Revision si vous visez aussi des serveurs plus anciens.
curl -X POST https://votre-site/api/v1/ecritures \
  -H "Authorization: Bearer clt_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: commande-1042" \
  -H "If-Match: 12" \
  -d '{ … }'

Réponses allégées : Prefer: return=minimal

Les réponses de /api/v1 ne contiennent que le résultat de l'opération ({ "ok": true, "ecriture": { … } }). L'API de l'application, /api/compta/…, renvoie en plus, par défaut, toute la comptabilité de la société après chaque modification ({ "res": { … }, "base": { … } }), ce qui pèse lourd pour une grosse société. Avec l'en-tête Prefer: return=minimal (RFC 7240), une modification renvoie seulement son résultat et la nouvelle révision, { "res": { … }, "revision": 42 }, avec l'en-tête Preference-Applied: return=minimal. Une modification qui renverrait la comptabilité ou les réglages seuls (PUT /settings, sur /api/v1 aussi) répond { "revision": 42 }. Les lectures et les réponses sans l'en-tête ne changent pas ; un renvoi idempotent sans l'en-tête renvoie la réponse complète.

Requêtes simultanées

Vous pouvez envoyer plusieurs modifications en parallèle : pour une même société, ComptaLT les traite l'une après l'autre, sans en perdre aucune. Les lectures ne sont jamais bloquées.

Société et réglages

RequêteDescription
GET /societeRésumé : nom, forme juridique, TVA (assujettie, taux, comptes 1170 impôt préalable et 2200 TVA due), modules activés, exercices. Le bon point de départ.
GET /settingsRéglages complets, dont facturation.prixTtcApiParDefaut : sens des prix des factures, devis et contrats reçus sans prixTTC ; facturation.termeConvenu : échéance convenue par contrat ou conditions générales (intérêts moratoires dès l'échéance, sinon dès la première relance, art. 102 CO).
PUT /settingsRemplace les réglages : lisez-les, modifiez les champs voulus, renvoyez l'objet entier. Répond avec les réglages enregistrés. Types contrôlés (400 détaillé, « Réglages invalides : … ») : entreprise, tva, tva.numerosComptes, facturation, modules sont des objets, leurs champs des textes, nombres ou indicateurs. Clé API de portée complete seulement (portées).

Plan comptable

RequêteDescription
GET /comptesTous les comptes : no, libelle, classe (1 à 8), type (actif, passif, charge, produit), tvaDefaut.
POST /comptesAjoute un compte : { "no": "3410", "libelle": "Ventes boutique en ligne", "classe": 3, "type": "produit" }.
PUT /comptes/{no}Modifie un compte (champs partiels).
DELETE /comptes/{no}Supprime un compte inutilisé.

Exercices

RequêteDescription
GET /exercicesListe [{ "annee": 2026, "cloture": false }].
POST /exercicesOuvre un exercice : { "annee": 2027 }.
POST /exercices/avec-ouvertureOuvre un exercice en reportant les soldes du bilan précédent.
POST /exercices/bornesExercice décalé ou premier exercice long : { "annee": 2026, "debut": "2025-07-01", "fin": "2026-06-30", "ouverture": true } (ouverture : soldes du bilan précédent reportés). Les rapports et leurs PDF suivent ces bornes.
POST /ouverture/{annee}/soldesPremier exercice : soldes de départ { "soldes": [{ "compteNo": "1020", "montant": 8500 }] }.
GET /ouverture/{annee}Aperçu de l'écriture d'ouverture.
POST /ouverture/{annee}Génère l'écriture d'ouverture ; /ouverture/{annee}/regenerer la recalcule.
DELETE /ouverture/{annee}Supprime l'écriture d'ouverture.
GET /exercices/{annee}/controlesPoints bloquants et avertissements avant clôture.
GET /exercices/{annee}/produits-avanceProduits encaissés d'avance : part des factures (de contrats) de l'exercice qui se rapporte à l'exercice suivant. POST sur la même adresse passe la régularisation au 31.12 (compte 2301), extournée au 01.01 de l'exercice suivant, hors du décompte TVA ; refusée (422) s'il n'y a rien à régulariser ou si c'est déjà fait.
POST /exercices/{annee}/cloturerClôture (verrouille la saisie).
POST /exercices/{annee}/rouvrirRouvre un exercice clôturé : { "motif": "Correction de la TVA du T4 demandée par la fiduciaire" }, motif obligatoire (5 caractères au moins, sinon 422), inscrit avec son auteur et sa date dans l'historique de l'exercice et imprimé dans le grand livre. /exercices/{annee}/reouverture est la même opération. Un exercice rouvert ne se supprime plus et une sauvegarde ne le réécrit plus.
GET /exercices/{annee}/bilan-suppressionCe qu'effacerait la suppression de l'exercice.
POST /exercices/{annee}/supprimerSuppression définitive, avec { "confirmation": "SUPPRIMER" }.

Écritures

Toute opération est une écriture en partie double : la somme des débits égale la somme des crédits, et chaque ligne porte soit un débit, soit un crédit. La date doit tomber dans l'exercice, qui doit être ouvert.

RequêteDescription
GET /ecritures?annee=2026Écritures de l'exercice, triées par date. Filtres facultatifs : depuis, jusqua (dates incluses), compte, recherche (dans le libellé), limite (les N plus récentes).
GET /ecritures/{id}Une écriture.
POST /ecrituresCrée une écriture, ou la modifie si le corps contient son id. Répond { "ok": true, "ecriture": { "id", "no", … } }. Un paiement de client (argent au débit, débiteurs au crédit) que le relevé bancaire a déjà encaissé peut être refusé (422, voir ci-dessous).
DELETE /ecritures/{id}Supprime une écriture d'un exercice ouvert, hors période TVA déclarée.
POST /ecritures/{id}/corrigerCorrection par extourne : { "correction": { "libelle", "lignes": [ … ], "date"? } }, ou { "correction": null } pour une simple annulation. L'écriture d'origine reste intacte ; une extourne datée du jour l'annule, puis la nouvelle version est passée (datée du jour sauf autre date hors période verrouillée). Répond { "ok": true, "extourne": { … }, "ecriture": { … } }.
POST /api/v1/ecritures
{
  "annee": 2026,
  "date": "2026-09-17",
  "libelle": "Loyer de septembre",
  "lignes": [
    { "compteNo": "6000", "debit": 1650, "credit": 0 },
    { "compteNo": "1020", "debit": 0,    "credit": 1650 }
  ]
}

decompteTva: true est réservé au paiement, au remboursement ou à la provision de la TVA (écriture exclue du décompte) : une écriture qui le porte ne touche que les comptes de TVA et l'argent. Posé sur une autre écriture (une vente, par exemple, qui sortirait ainsi du décompte), il est refusé (422). Le paiement de la TVA d'une période terminée (decompteTva: true, libellé qui nomme la période, par exemple « Décompte TVA T1 2026 ») la rend déclarée.

Paiement déjà encaissé par le relevé bancaire (422)

Une nouvelle écriture qui encaisse un débiteur (un compte d'argent au débit, les débiteurs au crédit du même montant) est refusée quand le relevé bancaire importé a déjà encaissé ce paiement : transaction du même compte et du même montant, à 31 jours près, rapprochée d'une facture, d'une commande ou d'une écriture de débiteurs, sans autre transaction de ce montant à traiter. L'enregistrer compterait l'argent deux fois. La réponse est 422 :

{ "erreur": "Ce paiement de 1081.00 CHF semble déjà enregistré : le relevé bancaire du 10.03.2026 l'a encaissé la facture 2026-0001 (Client SA). …",
  "code": "doublon_probable",
  "doublonProbable": { "transactionId": "…", "date": "2026-03-10", "montant": 1081, "compteNo": "1020" } }

S'il s'agit bien d'un autre paiement, renvoyez la même écriture avec "doublonConfirme": true ("true" et 1 sont acceptés) ; sinon, ne la renvoyez pas : le paiement est déjà en comptabilité. Pour encaisser une facture, préférez POST /factures/{id}/encaisser ou /paiements, qui tiennent compte du relevé.

Écritures verrouillées

Une écriture d'un exercice clôturé, ou qui entre dans le décompte d'une période TVA déclarée, ne se modifie plus (date, montants, comptes, drapeau decompteTva) et ne se supprime plus : POST /ecritures avec son id et DELETE /ecritures/{id} répondent 422 (« L'écriture n° 12 du 15.03.2026 ne se modifie plus : la période TVA T1 2026 est déclarée. Corrigez-la par une extourne datée du jour, puis une nouvelle écriture »). Seul son libellé se corrige. Corrigez-la par POST /ecritures/{id}/corriger. Une nouvelle écriture datée d'une période déclarée est refusée de même (422) : passez-la à une date de la période en cours.

Les montants debit et credit reçus par l'API sont arrondis au centime (un calcul de TVA par expression, par exemple 11.3894, devient 11.39). Si l'écriture reçue était équilibrée, l'écart d'arrondi (un centime par ligne au plus) est repris sur la ligne que l'arrondi a le plus déplacée (à égalité, sur un compte hors TVA) ; une écriture reçue déséquilibrée reste refusée (422). Un montant est un nombre JSON ou un texte décimal simple ("125.50") ; tout autre valeur (true, "0x10", "1e3", "12,50") est refusée (422). Envoyez de préférence des montants déjà arrondis.

Pièces jointes

RequêteDescription
POST /pieces/{ecritureId}Joint un justificatif : { "nom": "ticket.pdf", "donneesBase64": "…" }.
GET /pieces/contenu/{pieceId}Contenu en base64 : { "donneesBase64": "…" }.
DELETE /pieces/{ecritureId}/{pieceId}Retire la pièce.

Rapports, TVA et exports

RequêteDescription
GET /rapports/bilan?annee=2026Bilan (actifs, passifs, résultat).
GET /rapports/pertes-profits?annee=2026Compte de résultat.
GET /rapports/balance?annee=2026Débit, crédit et solde de chaque compte : le plus simple pour connaître la trésorerie.
GET /rapports/grand-livre?annee=2026Grand livre (art. 1 al. 2 Olico) : comptes (mouvements avec contrepartie et solde progressif), journal chronologique et controles (numérotation, équilibre).
GET /tva/decomptes?annee=2026Décomptes TVA de l'année (trimestres, ou semestres au TDFN), chacun avec formulaire : les chiffres du formulaire de l'AFC (chiffres : 200 à 299, impôt par taux avec sa base, 399, 400 et 405, 500 ou 510 ; parTaux : base et impôt par taux) et avertissements (points à vérifier avant de déclarer). Une période déclarée porte en plus declaration : { "le", "par", "source", "montantDeclare"?, "soldeRecalcule", "ecart", "chiffresDeclares"?, "correction"? } ; son soldeAPayer est alors le solde déclaré à l'AFC (montantDeclare, corrections déclarées ensuite comprises), jamais recalculé en silence. soldeRecalcule : décompte refait avec les écritures et les règles actuelles ; ecart : recalcul moins solde déclaré, à déclarer en correction (art. 72 LTVA) s'il est fondé (0 sous 5 centimes) ; chiffresDeclares : chiffres du formulaire au moment de la déclaration ; correction : écriture proposée dans la période en cours ({ "libelle", "lignes" }). Le PDF (/exports/tva) les imprime.
GET /tva/declarationsPériodes TVA déclarées : [{ "annee", "periode", "debut", "fin", "le", "par", "source" }] (source : paiement, action ou migration). Leurs écritures du décompte sont verrouillées.
POST /tva/declarationsDéclare une période terminée : { "annee": 2026, "periode": "T1" } (T1 à T4, ou S1, S2 au TDFN).
POST /tva/declarations/{annee}/{periode}/annulerRetire une période marquée déclarée par erreur : { "motif": "…" } (obligatoire, inscrit dans la piste d'audit). Une période réellement déclarée à l'AFC se corrige dans la période en cours.
GET /exports/{type}?annee=2026Fichier PDF : bilan, pp, balance, grand-livre, tva (avec &trimestre=1) ; Excel : grand-livre.xlsx.
GET /exports/facture?id=…PDF d'une facture avec QR-facture du solde ouvert (règlements reçus imprimés sous le total) ; rappel de la dernière relance d'une facture encore ouverte (&relance=2 pour un niveau précis, &relance=0 sans rappel). Un avoir (« Avoir », facture d'origine, montant en faveur du client), un brouillon (« Brouillon », sans numéro) et une facture annulée ou payée n'ont pas de QR-facture. Fichier Facture-2026-0001.pdf, Avoir-2026-0002.pdf ou Facture-brouillon.pdf. /exports/devis?id=… pour un devis.
GET /rapports/annexe?annee=2026Annexe minimale aux comptes annuels (art. 959c CO) : rubriques avec leur texte et leur référence légale ; /rapports/annexe/pdf?annee=2026 pour le PDF.

Les rapports PDF, le grand livre Excel et les fichiers d'échange sont produits en arrière-plan, quelques-uns à la fois pour toute la plateforme. Quand trop d'exports sont déjà en cours, ou si un export dépasse le délai maximal (deux minutes par défaut), la réponse est 503 avec l'en-tête Retry-After (en secondes, par exemple Retry-After: 60) et { "erreur": "Trop d'exports sont en cours sur la plateforme : réessayez dans une minute." } : attendez ce délai avant de redemander le fichier, sans boucle de nouvelles tentatives immédiates. Les PDF d'une facture ou d'un devis ne sont pas concernés.

Clients

RequêteDescription
GET /clientsFichier clients. /clients/{id} pour un seul.
POST /clientsCrée (ou modifie avec id) : nom obligatoire, adresse, npaLocalite, pays (CH), email, telephone, notes.
DELETE /clients/{id}Supprime un client sans contrat en cours.

Factures

Cycle : brouillon (sans numéro) → émise (numéro définitif, écriture débiteurs / produits) → payée en partie (partielle) → payée (écriture argent / débiteurs), ou annulée. Une facture émise se corrige par un avoir.

RequêteDescription
GET /factures?annee=2026Factures et avoirs (année facultative), avec leurs totaux : net, tva, brut, rabais, parTaux, et leur solde ouvert. statut : brouillon, emise, partielle, payee ou annulee. /factures/{id} pour une seule.
POST /facturesCrée un brouillon (ou le modifie avec id), voir le guide. Une facture émise garde son montant et sa date sous son numéro : les changer répond 422 (code refus ; correction par un avoir, ou annulation d'une facture non payée) ; son adresse, son client, son objet, ses notes et son échéance restent modifiables. Sens des prix des lignes, à préciser : "prixTTC": false, prix hors TVA, la TVA s'ajoute par taux ; "prixTTC": true, prix TVA comprise, le total est la somme des lignes et la facture indique « dont TVA ». Les formes texte "true"/"false" et 1/0 sont acceptées, toute autre valeur est refusée (422). Sans prixTTC : selon le réglage de la société facturation.prixTtcApiParDefaut (GET /settings, modifiable par PUT /settings) — hors TVA pour une société créée depuis le 04.10.2026 ; TVA comprise pour une société au TDFN qui utilisait déjà l'API (même total qu'avant). Une facture modifiée garde son sens.
POST /factures/{id}/emettreNuméro définitif (attribué maintenant), totaux figés et passage en comptabilité. Répond { "ok": true, "facture": { "numero": "2026-0007", … } }.
POST /factures/{id}/encaisserPaiement du solde : { "compteArgentNo": "1020", "datePaiement": "2026-10-15" } (le total d'une facture émise, ce qui reste d'une facture payée en partie).
POST /factures/{id}/paiementsPaiement complet ou partiel : { "compteArgentNo": "1020", "datePaiement": "2026-10-15", "montant": 500 } ; escompte (escompte accordé, TVA due corrigée), montantRecu (francs réellement reçus pour une facture en devise : différence de change). Sans montant, le solde. Un montant au-delà du solde est refusé (422). Répond { "ok", "facture", "paiement" }.
DELETE /factures/{id}/paiements/{paiementId}Retire un règlement erroné (et l'escompte qui lui est lié) ; refusé (422) pour un paiement rapproché du relevé bancaire : annulez d'abord le rapprochement.
POST /factures/{id}/pertePerte sur débiteur : { "date": "2026-12-31", "montant": 120 } (sans montant : tout le solde).
POST /factures/{id}/avoirÉtablit un avoir : { "date": "2026-10-20", "motif": "Prestation non réalisée" } pour toute la facture, ou avec lignes (montants positifs crédités) pour une partie. Répond { "ok", "avoir", "facture" }.
POST /factures/{id}/rembourserRembourse au client le reste d'un avoir : { "compteArgentNo": "1020", "date": "2026-10-25" } (montant facultatif).
POST /factures/{id}/relancesRelance une facture échue : { "date": "2026-10-04", "interets": true } (intérêts moratoires de 5 % l'an, art. 104 CO, ou taux convenu), courus dès la première relance (mise en demeure, art. 102 al. 1 CO), ou dès l'échéance si le réglage facturation.termeConvenu est vrai (échéance convenue, art. 102 al. 2 CO). Pour un rappel donné, "depuis": "echeance" (échéance convenue avec ce client) ou "depuis": "mise-en-demeure" remplace le réglage ; toute autre valeur est refusée (422). Le PDF de la facture imprime alors le rappel.
GET /factures/relances?date=2026-10-04Factures échues à relancer : [{ "factureId", "numero", "client", "echeance", "joursRetard", "soldeOuvert", "niveau", "derniereRelance"?, "interets" }].
POST /factures/{id}/annulerAnnule une facture émise et non réglée (écriture extournée). Une facture payée ou payée en partie se corrige par un avoir (422).
POST /factures/{id}/envoyerEnvoie le PDF par e-mail au client (si l'envoi est configuré). Un brouillon part comme tel (« Facture (brouillon) », PDF marqué « Brouillon », sans QR-facture) : émettez la facture avant de l'envoyer pour paiement.
DELETE /factures/{id}Supprime un brouillon.

Devis et opportunités

RequêteDescription
GET /devis?annee=2026Devis.
POST /devisCrée ou modifie : mêmes champs qu'une facture (dont prixTTC, facultatif), plus validiteJusquau et opportuniteId.
POST /devis/{id}/statut{ "statut": "envoye" } : brouillon, envoye, accepte, refuse.
POST /devis/{id}/facturerCrée la facture brouillon correspondante.
DELETE /devis/{id}Supprime un devis.
GET /opportunitesSuivi des ventes.
POST /opportunitestitre, montantEstime, client ou clientId, etape, dateRelance, notes.
POST /opportunites/{id}/etapeprospect, contact, devis, negociation, gagne, perdu.
POST /opportunites/{id}/facturerFacture une opportunité gagnée.
DELETE /opportunites/{id}Supprime une opportunité.

Contrats récurrents

RequêteDescription
GET /contratsContrats.
POST /contratsclientId, objet, lignes, periodicite (mensuel, trimestriel, semestriel, annuel), dateDebut, joursAvant, nombrePeriodes, envoiAuto, prixTTC (facultatif, comme pour une facture : prix des factures établies TVA comprise).
POST /contrats/{id}/statutactif, suspendu, termine.
POST /contrats/genererÉtablit tout de suite les factures arrivées à échéance (fait aussi automatiquement chaque heure).
DELETE /contrats/{id}Supprime un contrat.

Stock

RequêteDescription
GET /stock/articlesArticles avec quantité, valeur et coût moyen pondéré.
POST /stock/articles{ "no": "SKU-1042", "libelle": "Bougie parfumée", "unite": "pce" } ; compteStock (1200) et compteAchat (4200) facultatifs. Répond avec l'article et son id.
PUT /stock/articles/{id}Modifie un article.
DELETE /stock/articles/{id}Supprime un article sans mouvement.
GET /stock/articles/{id}/mouvementsHistorique de l'article.
POST /stock/mouvementsarticleId, date, type (entree, sortie, inventaire), quantite, prixUnitaire, libelle, ecritureId facultatif.

Canaux de vente

Un canal regroupe les réglages comptables d'une source de ventes : une boutique, une caisse, un prestataire de paiement. Son code (minuscules, chiffres, ., _, -) est choisi par le logiciel qui l'alimente. Un canal inconnu est créé avec les valeurs par défaut à la première commande.

RequêteDescription
GET /canauxListe. /canaux/{code} pour un seul.
PUT /canaux/{code}Crée ou met à jour (champs partiels) : nom, type, mode, stock, comptes, actif.
DELETE /canaux/{code}Supprime un canal sans opération.
PUT /api/v1/canaux/prestashop-1
{
  "nom": "Boutique PrestaShop",
  "type": "prestashop",
  "mode": "ecritures",
  "stock": "mouvements",
  "comptes": {
    "ventesNormal": "3200", "ventesReduit": "3201", "ventesHebergement": "3401", "ventesExonere": "3200",
    "fraisPort": "",
    "encaissement": { "*": "1020", "carte": "1030", "paypal": "1036", "twint": "1037" },
    "frais": "6900", "debiteurs": "1100", "banque": "1020"
  }
}
ChampValeurs
typeprestashop, woocommerce, shopify, stripe, sumup, wallee, postfinance-checkout, caisse, api.
modeecritures (défaut : une écriture par vente) ou factures (une facture ComptaLT émise puis encaissée par commande).
stockmouvements : chaque vente sort les articles par référence, les retours les remettent ; quantites : la boutique envoie ses quantités ; aucun. N'envoyez jamais les quantités en mode mouvements (double décompte).
comptes.encaissementMoyen de paiement → compte d'argent ; * pour les autres. Moyens conseillés : carte, twint, paypal, postfinance, virement, facture, especes, autre. Un compte 1000–1099 absent est créé (« en transit »).

Commandes

La façon la plus simple de relier une boutique : envoyez la commande telle quelle, ComptaLT calcule la TVA par taux, passe l'écriture (ou la facture), l'encaissement, la commission et la sortie de stock. Une commande renvoyée n'est jamais comptée deux fois : canal + reference l'identifient durablement.

curl -X POST https://votre-site/api/v1/commandes \
  -H "Authorization: Bearer clt_VOTRE_CLE" -H "Content-Type: application/json" \
  -d '{
    "canal": "prestashop-1", "reference": "1042", "numero": "XKBKNABJK", "date": "2026-09-17",
    "prixTTC": true,
    "client": { "nom": "Marie Dupont", "email": "marie@exemple.ch", "npaLocalite": "1800 Vevey", "pays": "CH" },
    "lignes": [
      { "reference": "BOUG-01", "description": "Bougie parfumée", "quantite": 2, "prixUnitaire": 25.00, "tauxTva": 8.1 },
      { "reference": "LIV-12", "description": "Livre de recettes", "quantite": 1, "prixUnitaire": 30.00, "tauxTva": 2.6 },
      { "type": "port", "description": "Poste CH", "montant": 7.00, "tauxTva": 8.1 },
      { "type": "rabais", "description": "Code BIENVENUE", "montant": 5.00, "tauxTva": 8.1 }
    ],
    "total": 82.00,
    "paiement": { "moyen": "carte", "frais": 1.50, "reference": "pi_3Nabc" }
  }'
# → { "ok": true, "dejaEnregistree": false, "commande": { "statut": "payee", "totalTtc": 82, "totalTva": 4.66,
#      "ventilation": [{ "taux": 8.1, "compte": "3200", "ht": 48.1, "tva": 3.9, "ttc": 52 }, …], "avertissements": [] } }
ChampRègle
referenceUnique par canal (≤ 100 caractères). PrestaShop : l'id_order ; WooCommerce : l'ID de commande.
prixTTCtrue par défaut : prixUnitaire et montant sont TVA comprise ; false : hors TVA, la TVA s'ajoute par taux.
lignes[].typearticle (défaut), port, frais, rabais (montant positif déduit).
lignes[].montantTotal de la ligne après rabais ; à défaut quantite × prixUnitaire.
lignes[].tvaFacultatif : TVA de la ligne telle que calculée par la boutique, reprise exactement si toutes les lignes l'ont.
totalMontant payé par le client, toujours TVA comprise (quel que soit prixTTC). Contrôle : un écart d'arrondi ≤ 0.10 CHF est absorbé (avertissement), au-delà la commande est refusée (422).
devise / tauxChangeAutre devise que le CHF : tauxChange (CHF pour 1 unité) obligatoire.
paiementAbsent : commande à encaisser (débiteurs). frais = commission. Commande en devise : montantChf (francs réellement reçus, par exemple d'après le relevé bancaire) n'est jamais reconverti ; l'écart avec le montant au cours de la commande est une différence de change (gain 6950, perte 6900), à 10 % près (422 au-delà). Les paiements partiels ne sont pas pris en charge.

Les avertissements ne bloquent pas (article inconnu du stock, stock insuffisant, exercice ouvert automatiquement, taux de TVA étranger, écart d'arrondi) : affichez-les dans le journal de votre connecteur. Une date dans l'année qui suit le dernier exercice ouvre cet exercice automatiquement ; un exercice clôturé refuse la commande.

RequêteDescription
GET /commandesListe, plus récentes d'abord. Filtres : canal, statut (a-encaisser, payee, remboursee-partiellement, remboursee, annulee), depuis, jusqua, recherche, limite.
GET /commandes/{canal}/{reference}Une commande (404 si inconnue).
POST /commandes/{canal}/{reference}/paiementSolde une commande non payée : { "date": "2026-09-20", "moyen": "virement", "frais": 0 }. Commande en devise : { "date": "2026-09-20", "moyen": "virement", "montantChf": 935.20 }, francs reçus (différence de change passée).
POST /commandes/{canal}/{reference}/remboursementsRemboursement total ou partiel, voir ci-dessous.
POST /commandes/{canal}/{reference}/annuler{ "date", "motif", "retourStock": true } : créance extournée si non payée, solde remboursé sinon. Rejouable.
POST /api/v1/commandes/prestashop-1/1042/remboursements
{
  "reference": "avoir-17",
  "date": "2026-09-25",
  "montantTtc": 32.00,
  "retours": [{ "reference": "BOUG-01", "quantite": 1 }],
  "motif": "Article abîmé"
}

Paiements isolés et versements

Pour un prestataire de paiement sans détail d'articles (lien de paiement, terminal, facture payée en ligne).

POST /api/v1/paiements
{ "canal": "stripe", "reference": "pi_3Nabc", "date": "2026-09-17", "montant": 108.10, "frais": 3.35,
  "moyen": "twint", "description": "Atelier du 20 septembre", "tauxTva": 8.1, "compte": "3400",
  "factureNumero": "2026-0012" }
POST /api/v1/paiements/versements
{ "canal": "stripe", "reference": "po_1Nxyz", "date": "2026-09-19", "montant": 1045.30, "frais": 0 }
# Écriture : banque du canal au débit, compte d'encaissement (en transit) du canal au crédit.

Catalogue par référence

RequêteDescription
GET /stock/articles/reference/{reference}L'article dont le numéro est la référence (SKU).
PUT /stock/articles/reference/{reference}Crée ou met à jour : libelle (obligatoire à la création), unite, seuilAlerte, compteStock, compteAchat, quantite (inventaire si elle diffère), prixAchat (valorisation), date. Répond { "ok", "cree", "article", "mouvement" }.
POST /stock/articles/lot{ "articles": [{ "reference": "BOUG-01", "libelle": "…" }, …] }, 500 au plus. Répond un résultat par article.

Fournisseurs et factures fournisseurs

RequêteDescription
GET /fournisseursFichier des fournisseurs. /fournisseurs/{id} pour un seul.
POST /fournisseursCrée (ou modifie avec id) : nom, adresse, npaLocalite, pays, email, iban, ide, compteCharge, tauxTva, conditionsJours.
GET /fournisseurs/facturesFactures reçues ; filtres statut (a-payer, payee, annulee), annee, fournisseur.
POST /fournisseurs/facturesEnregistre et comptabilise (charges, impôt préalable, créanciers 2000). Le fournisseur inconnu est créé. pieceJointe: { nom, donneesBase64 } joint le justificatif.
POST /fournisseurs/factures/{id}/payer{ "compteArgentNo": "1020", "datePaiement": "2026-10-10" }. /annuler-paiement et /annuler reviennent en arrière.
POST /fournisseurs/factures/lire-qr{ "contenu": "SPC\n0200\n1\n…" } : décode une QR-facture suisse (y compris les informations Swico S1 : numéro, date, TVA, conditions) et renvoie une proposition de facture, sans rien enregistrer.
POST /api/v1/fournisseurs/factures
{
  "fournisseur": { "nom": "Swisscom SA", "iban": "CH93 0076 2011 6238 5295 7" },
  "numero": "F-88123", "date": "2026-09-10", "echeance": "2026-10-10",
  "lignes": [{ "description": "Abonnement internet", "montant": 64.90, "tauxTva": 8.1, "compteCharge": "6570" }],
  "referencePaiement": "210000000003139471430009017"
}

lignes[].montant est TVA comprise : l'impôt préalable est extrait selon tauxTva (sauf méthode forfaitaire). Une ligne avec articleId et quantite fait entrer la marchandise en stock (au coût HT). Le paiement par le rapprochement bancaire solde la facture automatiquement quand la référence correspond.

Relevés bancaires et rapprochement

Formats reconnus : camt.053, camt.052 et camt.054 (ISO 20022, normes SIX), MT940 et CSV (PostFinance, UBS, Raiffeisen, exports génériques ; correspondance des colonnes détectée ou fournie). Les fichiers s'envoient en texte (contenu) ou en base64 (contenuBase64, UTF-8 ou Windows-1252). Un mouvement déjà importé est ignoré, y compris un paiement QR reçu d'abord par un avis camt.054 puis par le relevé camt.053 (même compte, date, montant et référence).

RequêteDescription
POST /banque/analyser{ "nom", "contenu", "iban"? } : format, IBAN, période, solde final, nombre de mouvements, de doublons et de doublons probables (doublonsProbables), aperçu, colonnes CSV. Un relevé camt qui contient plusieurs comptes donne comptes ([{ "iban", "mouvements" }]) et n'analyse que le compte iban demandé (par défaut le premier). N'enregistre rien.
POST /banque/imports{ "nom": "releve.xml", "contenu", "compteNo": "1020", "iban"?, "correspondanceCsv"?, "rapprochementAuto"? } : importe et rapproche automatiquement les cas sûrs (référence QR d'une facture au bon montant, facture fournisseur, règles automatiques). Relevé camt à plusieurs comptes : seuls les mouvements du compte iban (par défaut celui déjà associé à compteNo, sinon le premier) ; un iban absent du fichier est refusé (422). Répond aussi ecartSolde (solde final du relevé moins solde comptable du compte à la même date) et doublonsProbables (mouvements probablement déjà reçus d'un autre fichier, jamais rapprochés automatiquement).
GET /banque/transactionsFiltres statut, compte, depuis, jusqua, import ; pagination limite et decalage (transactions sautées). Les transactions a-traiter portent des suggestions ; doublonProbable signale un mouvement probablement déjà importé.
GET /banque/transactions/pageMêmes filtres, réponse { "transactions": [ … ], "total": 1240 } : 100 transactions par défaut, 500 au plus (limite), à partir de decalage.
GET /banque/ecarts?annee=2026Pour chaque relevé importé avec un solde final (de l'exercice annee, ou de tous) : écart actuel avec la comptabilité, [{ "importId", "fichier", "compteNo", "date", "soldeReleve", "soldeComptable", "ecart" }]. L'écart non nul du dernier relevé d'un compte bloque la clôture d'un exercice ouvert depuis le 04.10.2026 (simple avertissement pour les exercices plus anciens).
POST /banque/transactions/{id}/rapprocherUne suggestion telle quelle, ou { "action": "creer-ecriture", "compteNo": "6570", "tauxTva": 8.1 }. Actions : encaisser-facture, payer-facture-fournisseur, encaisser-commande, lier-ecriture, creer-ecriture, virement.
POST /banque/transactions/{id}/ignorerAucune écriture nécessaire. /retablir annule un rapprochement ou un « ignoré ».
POST /banque/rapprochement-autoApplique toutes les suggestions sûres.
GET /banque/reglesRègles ; POST /banque/regles { "nom", "contient": "SWISSCOM", "sens": "sortie", "compteNo": "6570", "tauxTva": 8.1, "automatique": true } ; DELETE /banque/regles/{id}.
GET /banque/importsRelevés importés ; DELETE /banque/imports/{id} retire ses transactions non rapprochées.

Caisse

RequêteDescription
POST /caisse/cloturesUne journée : { "canal": "caisse", "date", "reference": "Z-0412", "ventes": [{ "tauxTva": 8.1, "montant": 1081 }], "encaissements": [{ "moyen": "especes", "montant": 400 }, { "moyen": "carte", "montant": 681 }] }. Écart encaissé − ventes : excédent (3600) ou manque (6700). Idempotent par canal et référence (ou date).
GET /caisse/clotures?annee=2026Clôtures. DELETE /caisse/clotures/{id} retire aussi l'écriture.
POST /caisse/import{ "contenu" | "contenuBase64", "canal" } : CSV date;reference;ventes_8.1;ventes_2.6;especes;carte;twint;notes (autres moyens : postfinance, paypal, facture, bons, encaisse_…). Un résultat par ligne.

Boutiques en ligne : modules prêts à installer

1

PrestaShop

1.7.8 à 9. Télécharger le module, puis Modules → Téléverser. File d'attente avec nouvelles tentatives, avoirs, multiboutique, synchronisation du catalogue.

2

WooCommerce

WordPress 6.2+, HPOS. Télécharger l'extension, puis Extensions → Téléverser. Traitement en arrière-plan par Action Scheduler.

3

Shopify

Sans installation : créez une connexion directe dans l'application, puis les webhooks dans Paramètres → Notifications.

Les modules suivent exactement l'API ci-dessus : PUT /canaux/{code} à l'enregistrement de la configuration, POST /commandes au paiement, /remboursements pour les avoirs, /annuler, PUT /stock/articles/reference/{sku} pour le catalogue. Les erreurs 5xx, 429 et réseau sont réessayées ; 4xx et 422 attendent une correction puis un renvoi manuel.

Paiements en ligne et Shopify : connexions directes

Dans « API et intégrations », une connexion reçoit une adresse secrète https://votre-site/api/connecteurs/cx_… que vous indiquez à la plateforme. ComptaLT vérifie la signature, comptabilise, et tient un journal ; un événement refusé par la comptabilité (exercice manquant…) répond 200 à la plateforme et reste à rejouer après correction.

PlateformeÉvénements à abonnerSécurité
Shopifyorders/paid, refunds/create, orders/cancelled, products/create, products/update, inventory_levels/update (mode quantites)HMAC-SHA256 X-Shopify-Hmac-Sha256 avec la clé de signature des webhooks.
Stripe (cartes, TWINT…)charge.succeeded, charge.captured, charge.refunded, payout.paidStripe-Signature (fenêtre de 5 min). Clé API restreinte facultative pour les commissions et les devises.
Wallee, PostFinance CheckoutTransaction à l'état FULFILL, Remboursement SUCCESSFULLa notification ne sert que de signal : les données sont relues par l'API avec l'utilisateur d'application (authentification MAC).
SumUpCheckouts : return_url = adresse de réception. Terminaux : synchronisation horaire des journées complètes en clôtures de caisse.Données relues par l'API avec la clé SumUp.
Les connecteurs Wallee, PostFinance Checkout et SumUp suivent la documentation publique de ces prestataires : testez-les avec un compte de test avant la mise en production.

n8n, Zapier et Make

OutilContenuInstallation
n8nNœud « ComptaLT » (écritures, factures, clients, commandes, paiements, articles, factures fournisseurs, rapports) et « ComptaLT Trigger » (webhook signé).n8n auto-hébergé : Settings → Community Nodes → n8n-nodes-comptalt (paquet npm), ou installation manuelle depuis integrations/n8n/n8n-nodes-comptalt.
ZapierDéclencheurs instantanés (nouvelle commande, facture émise, payée en partie, payée ou soldée, paiement retiré, avoir émis ou annulé, nouveau client, stock bas, facture fournisseur, transaction rapprochée), actions et recherches.Application privée publiée avec la CLI Zapier (zapier push, dossier integrations/zapier/comptalt-zapier), puis invitation des utilisateurs.
MakeApplication personnalisée : modules d'action et de recherche, déclencheurs instantanés.Application personnalisée déployée avec l'extension Make pour VS Code (dossier integrations/make/comptalt-make).

Tous se connectent avec l'adresse de ComptaLT et une clé API ; les déclencheurs créent et suppriment eux-mêmes leur webhook.

Webhooks : abonnements

RequêteDescription
POST /webhooks{ "url": "https://…", "evenements": ["commande.enregistree"], "description", "source" } (["*"] = tous). Répond le webhook avec son secret, affiché cette fois seulement.
GET /webhooksListe, sans les secrets.
PUT /webhooks/{id}url, evenements, description, actif. Par une clé API : ses propres abonnements seulement (voir portées des clés), et une réactivation seulement de ce qu'elle a désactivé.
DELETE /webhooks/{id}Supprime l'abonnement (les livraisons en attente sont abandonnées).
POST /webhooks/{id}/secretGénère un nouveau secret.
POST /webhooks/{id}/testEnvoie un événement ping et répond le résultat.
GET /webhooks/{id}/livraisons100 dernières livraisons (statut, essais, réponses). POST /webhooks/livraisons/{id}/renvoyer.
GET /webhooks/evenementsCatalogue des types d'événements.

Chaque livraison est un POST JSON ; une réponse 2xx en moins de 10 secondes la valide, sinon ComptaLT réessaie après 1 min, 5 min, 30 min, 2 h, 6 h et 24 h. L'adresse doit être en https et publique (les adresses internes sont refusées).

{
  "id": "evt_Yd0…", "type": "facture.payee", "creeLe": "2026-09-17T08:00:00.000Z", "societe": "Boutique Léman",
  "donnees": { … la facture … }
}

Événements

Typedonnees
ecriture.creee, ecriture.modifiee, ecriture.supprimeeL'écriture (pour une suppression : id, no, annee, date, libelle).
facture.creee, facture.emise, facture.payee, facture.annuleeLa facture client avec ses totaux (net, tva, brut) et son solde ouvert. facture.creee : brouillon, numero vide (le numéro arrive avec facture.emise). facture.emise : une seule fois, à l'émission, jamais pour un avoir. facture.payee : le paiement qui solde la facture, jamais un paiement partiel.
facture.paiement_partielLa facture, restée ouverte (statut partielle) après un règlement partiel : paiement, avoir imputé ou perte partielle (paiements[].nature) ; solde = ce qui reste à payer.
facture.soldeeLa facture, soldée sans paiement de son solde : avoir imputé ou perte sur débiteur (statut payee, mais rien n'a été encaissé pour ce solde).
facture.paiement_annuleLa facture dont un règlement est retiré (paiement erroné, rapprochement bancaire annulé, avoir annulé) : elle redevient emise ou partielle.
avoir.emis, avoir.annuleL'avoir (total négatif) avec ses totaux, son solde (négatif : reste à rembourser), avoirDe et factureOrigine ({ "id", "numero" }).
client.cree, client.modifieLe client.
commande.enregistree, commande.payee, commande.remboursee, commande.annuleeLa commande (ou le paiement en ligne).
article.cree, article.modifie, stock.mouvement, stock.alerteL'article ; pour un mouvement { mouvement, article } ; l'alerte part quand un article passe sous son seuil.
fournisseur.facture.enregistree, fournisseur.facture.payeeLa facture fournisseur.
banque.releve.importe, banque.transaction.rapprocheeL'import ou la transaction.
caisse.cloture.enregistreeLa clôture de caisse.
exercice.cloture{ annee }.
ping{ message } (test).

Les événements naissent de toute modification : application, API, agent IA, connexion directe ou tâche planifiée.

Depuis le 04.10.2026, un avoir n'est jamais annoncé par facture.creee, facture.emise, facture.payee ni facture.annulee (son total négatif déclencherait les actions d'une facture) ; facture.emise n'est plus renvoyé quand un paiement est retiré (facture.paiement_annule) ; facture.payee ne part qu'au paiement qui solde la facture. Un abonnement ["*"] reçoit aussi les nouveaux types : ignorez ceux que votre intégration ne connaît pas.

Vérifier la signature

L'en-tête ComptaLT-Signature: t=1726567200,v1=5f3c… contient l'horodatage et HMAC-SHA256(secret, "{t}.{corps brut}") en hexadécimal. Calculez-le sur le corps brut, comparez en temps constant et refusez un horodatage de plus de 5 minutes. ComptaLT-Livraison identifie la livraison (utile pour ignorer un doublon).

import { createHmac, timingSafeEqual } from 'node:crypto'

export function signatureValide(corpsBrut, entete, secret) {
  const parties = Object.fromEntries(entete.split(',').map((p) => p.split('=')))
  if (Math.abs(Date.now() / 1000 - Number(parties.t)) > 300) return false
  const attendue = createHmac('sha256', secret).update(`${parties.t}.${corpsBrut}`).digest('hex')
  return attendue.length === parties.v1.length && timingSafeEqual(Buffer.from(attendue), Buffer.from(parties.v1))
}

Guide : facturer par l'API

# 1. Brouillon
POST /api/v1/factures
{
  "date": "2026-09-17", "annee": 2026,
  "client": { "nom": "Atelier Rossier Sàrl", "adresse": "Rue du Lac 4",
              "npaLocalite": "1800 Vevey", "pays": "CH", "email": "compta@rossier.ch" },
  "objet": "Refonte du site",
  "lignes": [
    { "description": "Conception", "quantite": 12, "prixUnitaire": 120,
      "tauxTva": 8.1, "compteProduit": "3400" }
  ]
}
# → { "ok": true, "facture": { "id": "…", "numero": "", "statut": "brouillon", … } }
# Le brouillon n'a pas encore de numéro.
# Sans "prixTTC" : selon facturation.prixTtcApiParDefaut (hors TVA pour une nouvelle société, 8.1 % en sus).
# Précisez-le : "prixTTC": false, 120 hors TVA ; "prixTTC": true, 120 TVA comprise (« dont TVA »).

# 2. Émission (le numéro est attribué ici), envoi, puis encaissement
POST /api/v1/factures/{id}/emettre
# → { "ok": true, "facture": { "numero": "2026-0012", "statut": "emise", … } }
POST /api/v1/factures/{id}/envoyer
POST /api/v1/factures/{id}/encaisser   { "compteArgentNo": "1020", "datePaiement": "2026-10-10" }

# Paiement partiel : la facture passe « partielle », solde = ce qui reste à payer
POST /api/v1/factures/{id}/paiements   { "compteArgentNo": "1020", "datePaiement": "2026-10-10", "montant": 500 }

# Correction d'une facture émise : avoir (toute la facture, ou des lignes), puis remboursement du reste
POST /api/v1/factures/{id}/avoir       { "date": "2026-10-20", "motif": "Prestation non réalisée" }
POST /api/v1/factures/{avoirId}/rembourser   { "compteArgentNo": "1020", "date": "2026-10-25" }

# PDF avec QR-facture du solde ouvert
GET  /api/v1/exports/facture?id={id}

Connecter un agent IA (MCP)

Le Model Context Protocol permet à un assistant IA d'utiliser directement votre comptabilité : « enregistre les frais de ce ticket », « quel est mon résultat à fin août ? », « facture 12 heures à l'Atelier Rossier ». Le serveur MCP de ComptaLT utilise le transport Streamable HTTP et la même clé API que l'API REST : une clé en lecture seule ne montre à l'agent que les outils de consultation, une clé d'écriture que les outils de sa portée (tous avec une clé complete).

Adresse : https://votre-site/mcp
En-tête : Authorization: Bearer clt_VOTRE_CLE
claude mcp add --transport http comptalt https://votre-site/mcp \
  --header "Authorization: Bearer clt_VOTRE_CLE"

Outils disponibles

Chargement de la liste…

Protocole brut

Serveur sans session : chaque message JSON-RPC 2.0 est un POST /mcp qui reçoit sa réponse en JSON (les lots de messages sont traités dans l'ordre). Versions de protocole acceptées : 2025-06-18, 2025-03-26, 2024-11-05.

curl -X POST https://votre-site/mcp \
  -H "Authorization: Bearer clt_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/call",
        "params": { "name": "lister_ecritures",
                    "arguments": { "annee": 2026, "limite": 5 } } }'

Un outil refusé par la comptabilité répond normalement, avec "isError": true et le message d'erreur en texte : l'agent peut corriger et réessayer.

Bonnes pratiques de sécurité