L'API comptable KRONENWERK est une petite interface HTTPS documentée à l'adresse https://kronenwerk.org/api/extern/v1. Une clé API Bearer liée à exactement une entreprise lit les clients, les factures émises, les transactions et les postes ouverts, et crée des clients, des transactions et des brouillons de facture. Chaque écriture exige un Idempotency-Key. Les actes irréversibles — émettre une facture, enregistrer un paiement, annuler — ne sont pas exposés ; ils se produisent dans le produit et sont signalés en retour par des webhooks signés. L'API, les webhooks et le serveur MCP font partie du plan Enterprise.
À quoi sert l'API comptable
Elle est destinée aux logiciels qui doivent inscrire des enregistrements dans les livres d'une entreprise, ou lire ce qui est dû, sans qu'une personne recopie des chiffres entre deux systèmes. Les appelants typiques sont un back-end SaaS qui ouvre une transaction et un brouillon de facture lorsqu'un client signe un contrat, un tableau de bord interne qui lit les créances, ou un agent IA qui répond à « quelles factures sont en retard » via le serveur MCP.
Le principe de conception est que l'API atteint les mêmes services que les écrans. Il n'y a rien qu'un appelant externe puisse lire que le navigateur ne puisse pas lire, et rien qu'il puisse faire par un chemin plus court. La frontière entre locataires, la vérification du plan, la séquence de numérotation et les règles de chaque module pays sont appliquées une seule fois, dans le produit, et l'API en hérite. C'est pourquoi l'API accepte délibérément moins de champs que vous ne pourriez l'attendre : le numéro d'un brouillon, sa date d'échéance et sa mention de paiement proviennent de la juridiction du vendeur et des conditions convenues avec le client, pas de la requête.
Authentification : une clé, une entreprise
Vous vous authentifiez avec une clé API dans l'en-tête Authorization en tant que jeton Bearer. Les clés de production commencent par greif_live_, les clés de test par greif_test_. Une clé de test fonctionne contre le même hôte en mode test pour l'entreprise qui l'a créée ; il n'y a pas d'hôte sandbox séparé.
Une clé appartient à exactement une entreprise, décidée lors de l'émission de la clé et jamais modifiée ensuite. La colonne organisation de la clé n'est pas modifiable, le contexte d'action est construit à partir de cette colonne, et rien dans une requête ne peut l'influencer. Une personne membre de deux entreprises qui émet une clé en consultant l'entreprise A détient une clé qui ne pourra jamais lire l'entreprise B. GET /me le signale sous la forme d'un objet nommé binding, afin que vous le découvriez avant de construire sur l'hypothèse inverse.
Les clés portent des scopes choisis à la création de la clé :
| Scope | Ce qu'il permet |
|---|---|
customers:read | Lister et lire les clients |
customers:write | Créer des clients |
invoices:read | Lister et lire les factures émises |
invoices:write | Créer des brouillons de facture |
transactions:read | Lister les transactions (dossiers avec une étape et une date d'échéance) |
transactions:write | Créer des transactions |
reports:read | Lire le rapport des encours |
companies:read | Lire les paramètres de l'entreprise émettrice (nécessaire pour construire un brouillon) |
Un scope est un nom documenté pour un ensemble de capacités que le produit applique déjà ; ce n'est pas un second modèle de permissions. Les détails figurent sur la page d'authentification.
Endpoints : la liste complète
Ces dix adresses constituent toute l'interface. Le tableau de référence du portail développeurs est généré à partir de la même constante que le serveur applique, de sorte que le scope imprimé à côté d'une adresse est bien le scope vérifié à cette adresse.
| Méthode et chemin | Scopes requis | Retourne |
|---|---|---|
GET /me | aucun | La clé, son rattachement à une entreprise, l'environnement et les scopes |
GET /customers | customers:read | Une page de clients |
GET /customers/{id} | customers:read | Un client |
POST /customers | customers:write | 201 avec le client créé, y compris son numéro |
GET /invoices | invoices:read | Une page de factures émises, les plus récentes en premier ; filtres status (OPEN ou PAID), from, to |
GET /invoices/{number} | invoices:read | Une facture émise par son numéro |
POST /invoices/drafts | invoices:write customers:read companies:read | 201 avec un brouillon à l'état DRAFT |
GET /transactions | transactions:read | Une page de transactions ; filtres stage, search, includeArchived |
POST /transactions | transactions:write transactions:read | 201 avec la transaction créée et son numéro |
GET /reports/outstanding | reports:read | Créances et dettes ouvertes à ce jour |
Les listes sont paginées avec page (à partir de 0) et size (25 par défaut, 100 au maximum). Une page a la forme {"data": [...], "page": 0, "size": 25, "total": 137, "more": true}. Les montants sont toujours un nombre d'unités mineures accompagné d'un code devise — {"minor": 105910, "currency": "EUR"} — jamais une chaîne formatée. Les dates calendaires telles que issuedOn sont des dates ISO sans heure ; les horodatages tels que createdAt sont des instants.
Exemple : GET /me
Le premier appel à écrire, parce qu'il répond aux questions que se pose réellement une intégration mal configurée : est-ce que je parle à la bonne entreprise, est-ce la clé de test, quels scopes ai-je obtenus.
curl https://kronenwerk.org/api/extern/v1/me \
-H "Authorization: Bearer greif_test_…"
{
"organisationId": "5b1e…",
"organisation": "Beispiel GmbH",
"binding": { "organisationId": "5b1e…", "organisation": "Beispiel GmbH", "immutable": true },
"key": "greif_test_a1b2",
"name": "Billing service",
"environment": "SANDBOX",
"scopes": ["customers:read", "invoices:read", "transactions:write", "transactions:read"],
"permissions": ["EDIT_TRANSACTIONS", "VIEW_CUSTOMERS", "VIEW_INVOICES", "VIEW_TRANSACTIONS"],
"lastUsedAt": "2026-09-03T08:14:02Z",
"expiresAt": null
}
environment vaut SANDBOX pour une clé greif_test_ et PRODUCTION pour une clé greif_live_. scopes est le vocabulaire publié ; permissions est la liste interne des capacités qui décide réellement. Les deux sont renvoyés afin qu'une capacité sans scope la couvrant soit visible plutôt que cachée.
Exemple : POST /transactions avec un Idempotency-Key
Une transaction dans KRONENWERK est une unité de travail avec un titre, un client facultatif, une étape issue du flux de travail propre à l'entreprise et une date d'échéance — ce qu'une entreprise appelle un dossier ou une commande. Elle ne porte ni montant ni conséquence juridique, ce qui en fait l'écriture la moins cérémonieuse. Elle passe néanmoins par le même service que l'écran : le numéro est tiré de la séquence de l'entreprise pour l'année, l'étape est résolue par rapport aux étapes utilisées par cette entreprise, et un client appartenant à quelqu'un d'autre est refusé.
curl -X POST https://kronenwerk.org/api/extern/v1/transactions \
-H "Authorization: Bearer greif_live_…" \
-H "Idempotency-Key: order-2026-000481" \
-H "Content-Type: application/json" \
-d '{
"title": "Annual licence 2026/27 — Beispiel GmbH",
"customerId": "3f2b…",
"description": "Stripe subscription sub_1Q…",
"dueOn": "2026-09-30"
}'
{
"id": "9c7d…",
"number": "V2026-0481",
"title": "Annual licence 2026/27 — Beispiel GmbH",
"stage": "NEU",
"customer": "Beispiel GmbH",
"dueOn": "2026-09-30",
"archived": false,
"createdAt": "2026-09-03T08:15:41Z"
}
L'en-tête Idempotency-Key est obligatoire sur chaque POST, pas facultatif. La première requête sous une clé effectue le travail et la clé mémorise l'identifiant de ce qu'elle a créé ; une répétition sous la même clé relit cet enregistrement via la même vérification de locataire et le renvoie sans refaire le travail. Une répétition avec un corps différent sous la même clé est refusée avec 409 IDEMPOTENZ_KONFLIKT, parce qu'une clé désigne une seule opération voulue. Les clés peuvent compter jusqu'à 200 caractères, un numéro de commande avec préfixe convient donc. Deux copies de la même nouvelle tentative arrivant en même temps sont départagées par un index unique, pas par un « lire puis écrire ». Voir idempotence.
Erreurs et limites de débit
Chaque refus est un JSON avec une phrase pour une personne et un code pour un programme : {"fehler": "…", "code": "…"}. La phrase peut être reformulée à chaque version ; le code fait partie du contrat.
| Statut | Code | Signification |
|---|---|---|
| 400 | ANFRAGE | La requête n'a pas pu être lue : un champ manquant (la phrase le nomme), un corps non analysable |
| 401 | UNAUTHENTICATED | Pas de clé, une clé illisible, révoquée ou expirée — une seule réponse pour les quatre cas |
| 403 | PLAN_ERFORDERLICH | Le plan de l'entreprise n'inclut pas l'API ; seule la personne qui paie peut y remédier |
| 403 | KEINE_BERECHTIGUNG | La clé n'a pas le scope requis par cette adresse |
| 404 | NICHT_GEFUNDEN | Aucun enregistrement de ce type — y compris un enregistrement réel appartenant à une autre entreprise |
| 409 | IDEMPOTENZ_KONFLIKT | La clé d'idempotence a déjà été utilisée pour une requête différente, ou la même requête est encore en cours |
| 409 | FALSCHER_ZUSTAND | L'état de l'enregistrement ne permet pas cette opération |
| 409 | ABGELEHNT | Une règle métier a refusé la modification ; la phrase dit laquelle |
| 429 | ZU_VIELE_ANFRAGEN | Trop de requêtes pour cette clé ; accompagné de Retry-After |
Les deux 403 sont identiques sur la ligne de statut et exigent des actions totalement différentes, ce qui justifie l'existence du code. Un 404 est renvoyé délibérément pour « existe mais n'est pas à vous » : un 403 à cet endroit permettrait à un appelant de confirmer quels identifiants sont réels dans l'entreprise de quelqu'un d'autre.
La limite de débit est par clé, pas par adresse IP : un budget de 240 requêtes qui se reconstitue en continu à raison d'une requête toutes les 500 millisecondes, soit environ deux par seconde en régime soutenu avec de la marge pour les rafales. Lorsque le budget est épuisé, la réponse est 429 avec un en-tête Retry-After en secondes et un corps de la forme habituelle plus "wartesekunden". Une intégration qui a besoin de plus de débit est répartie sur deux clés, et les journaux indiquent alors quelle moitié est bruyante. Voir limites et erreurs.
Webhooks : comment les actes irréversibles vous parviennent
Émettre une facture consomme un numéro et libère un document juridique ; enregistrer un paiement modifie les livres ; annuler produit une correction. Aucun de ces actes n'a d'adresse sur l'API et aucun n'a de scope qui pourrait y mener. Ils sont signalés vers l'extérieur, sous forme de livraisons de webhooks signées pour les événements invoice.issued, invoice.paid, invoice.cancelled, purchase.recorded et payment.recorded.
Chaque livraison est un POST HTTPS vers l'endpoint que vous enregistrez, avec les en-têtes KRONENWERK-Signature (t=<unix seconds>,v1=<hex>, un HMAC-SHA256 sur l'horodatage, un point et le corps brut, avec une tolérance de cinq minutes), KRONENWERK-Event-Id, KRONENWERK-Event, KRONENWERK-Delivery, KRONENWERK-Attempt et Idempotency-Key (égal à l'identifiant de l'événement). Le corps est un objet JSON plat dont les valeurs sont des chaînes, avec des clés triées, et contient toujours "event" et "id". La livraison est « au moins une fois » avec nouvelles tentatives ; dédupliquez sur l'identifiant de l'événement. Seul HTTPS sur le port 443 est accepté, et les redirections ne sont pas suivies automatiquement — chaque cible de redirection est vérifiée selon les mêmes règles que l'adresse d'origine, et une chaîne de plus de trois sauts échoue. Les détails et un exemple de vérification figurent sur la page des webhooks.
MCP : les mêmes données pour les agents IA
Le serveur MCP à l'adresse https://kronenwerk.org/api/extern/mcp parle Streamable HTTP (POST uniquement, révision de protocole 2026-07-28, les trois révisions précédentes restant acceptées) et s'authentifie avec la même clé API Bearer. Il n'y a ni session ni paramètre d'organisation nulle part dans le protocole : l'entreprise qu'un agent atteint est celle de la clé, décidée avant le routage de la requête.
Outils de lecture : get_customer, search_customers, get_invoice, list_invoices, get_transaction, list_transactions, list_receivables, list_payables, get_profit_and_loss, get_balance_sheet, get_business_attention. Outils de brouillon : create_invoice_draft, create_transaction, add_transaction_note. Aucun outil n'émet de facture, n'envoie de courrier, ne déplace d'argent ni ne modifie de paramètres. Voir MCP.
Comment KRONENWERK gère cela
PRIS EN CHARGE L'API décrite ici est celle qui fonctionne aujourd'hui, à l'adresse https://kronenwerk.org/api/extern/v1. Elle est disponible dans le plan Enterprise avec les webhooks, le serveur MCP et l'annuaire des intégrations ; voir tarifs. Les clés sont créées dans les paramètres développeur du produit avec les scopes et l'environnement de votre choix, et GET /me vous indique ce que vous avez obtenu.
Ce qu'elle ne fait pas, dit clairement : elle n'émet pas de factures, n'enregistre pas de paiements, n'annule pas, n'envoie pas de factures électroniques et ne modifie pas de paramètres. Ce sont des actes qu'une personne accomplit dans le produit avec les validations que son pays et son activité y attachent — le verdict fiscal, la vérification VIES, la validation du fichier structuré et le numéro sans rupture de séquence s'y produisent tous. La page de l'API de facturation explique pourquoi la ligne est tracée exactement au brouillon, et connecter un produit SaaS montre la boucle complète de bout en bout. Commencez par le démarrage rapide et la référence.
Questions fréquentes
Existe-t-il un sandbox ?
Une clé greif_test_ fonctionne contre le même hôte en mode test pour l'entreprise qui l'a créée. Il n'existe pas d'hôte sandbox ni d'URL de base séparés.
Une clé API peut-elle accéder à plusieurs entreprises ?
Non. Une clé est liée à une entreprise lors de son émission et ce rattachement ne peut pas changer. Créez une clé par entreprise ; GET /me affiche le rattachement.
Pourquoi ne puis-je pas émettre une facture via l'API ?
Émettre consomme un numéro d'une séquence sans rupture, fige la ligne d'archive, produit le fichier structuré et, dans certains pays, le remet à un système étatique. Ce n'est pas une étape qu'une boucle exécutée deux fois devrait pouvoir franchir, elle reste donc dans le produit ; l'API crée des brouillons et le webhook invoice.issued vous indique quand une personne en a émis un.
Que se passe-t-il si j'oublie l'en-tête Idempotency-Key ?
Le POST est refusé avec 400. L'en-tête est exigé plutôt que proposé, parce qu'une garantie facultative ne protège que les appelants qui n'avaient pas besoin d'être protégés.
Comment les montants sont-ils représentés ?
Comme un nombre entier d'unités mineures plus un code devise, par exemple {"minor": 105910, "currency": "EUR"}. Jamais comme une chaîne formatée.
Quel plan inclut l'API ?
L'API, les webhooks, MCP et l'annuaire des intégrations font partie du plan Enterprise. Les prix actuels figurent sur la page des tarifs.
Sources
- KRONENWERK developer documentation — consulté le
- RFC 6750 — The OAuth 2.0 Authorization Framework: Bearer Token Usage — consulté le
- Model Context Protocol specification — consulté le