Développeurs
API REST
Lisez et écrivez la comptabilité d’une société depuis votre propre code, et soyez prévenu des changements par des webhooks signés. Cette page décrit les règles communes à tous les points d’accès ; le guide d’utilisation explique les notions.
Sur cette page
Vue d’ensemble
Chaque requête s’adresse à https://balancelyne.slimbennasrallah.com/api/v1, en HTTPS, avec des corps et des réponses JSON. Une clé donne accès à une seule société.
L’API est incluse dans les offres Plus et Advanced. Sur les autres offres, chaque appel répond 402 avec le code plan_feature.
curl https://balancelyne.slimbennasrallah.com/api/v1/company \
-H "Authorization: Bearer bal_…"Authentification
Les propriétaires et administrateurs créent des clés dans Paramètres → API. Une clé commence par bal_ et ne s’affiche qu’une fois : conservez-la dans un coffre à secrets, jamais dans du code front-end ni dans un dépôt.
Envoyez-la dans l’en-tête Authorization : Authorization: Bearer bal_…. Une clé agit avec le rôle de l’utilisateur qui l’a créée ; s’il quitte la société ou perd ce rôle, les appels échouent en 403. Révoquez une clé à tout moment depuis la même page.
Conventions
- Les montants sont des entiers en millimes :
1191000vaut 1 191,000 DT. Les autres devises utilisent aussi le millième d’unité. N’envoyez jamais de nombres à virgule. - Les taux sont en points de base :
1900vaut 19 %. - Les dates des pièces comptables sont au format
AAAA-MM-JJ(2026-11-13) ; les horodatages sont en ISO 8601, en UTC (2026-11-13T09:42:07Z). - Les identifiants sont des chaînes opaques. Les numéros de pièces (
FAC-2026-0042) sont faits pour les humains ; utiliseziddans votre code. - Les mises à jour sont partielles : n’envoyez que les champs modifiés.
- Les noms de champs sont en
camelCase; un champ inconnu est refusé en400.
curl -X POST https://balancelyne.slimbennasrallah.com/api/v1/<resource> \
-H "Authorization: Bearer bal_…" \
-H "Content-Type: application/json" \
-d '{ "…": "…" }'Pagination
Les listes acceptent page (à partir de 1) et limit (50 par défaut, 250 au plus) et renvoient le total, pour savoir quand s’arrêter.
{
"data": [ { "id": "cm3…", "…": "…" } ],
"page": 1,
"limit": 50,
"total": 214
}Erreurs
Une erreur renvoie un code HTTP et un corps JSON avec un message lisible error, et un code lorsque votre programme doit réagir.
| Code | Signification |
|---|---|
400 | Données invalides ; le message nomme le champ. |
401 | Clé absente, invalide ou révoquée. |
402 | plan_feature : l’offre n’inclut pas cette fonction. plan_limit : une limite de l’offre est atteinte (utilisateurs, documents de vente par mois, salariés). Également renvoyé lorsque l’abonnement a expiré et que la société est en lecture seule. |
403 | Le rôle du propriétaire de la clé ne le permet pas, ou il n’appartient plus à la société. |
404 | Point d’accès ou pièce inconnu (les pièces des autres sociétés ne sont jamais visibles). |
409 | Conflit, par exemple une période close par la date de clôture. |
423 | La société est suspendue. |
429 | Limite de débit atteinte. |
5xx | Erreur de notre côté. Réessayez plus tard avec la même requête. |
HTTP/1.1 402 Payment Required
{ "error": "The Essentials plan does not include this. Contact Balancelyne to upgrade.", "code": "plan_feature", "feature": "api" }Limites de débit
Chaque clé peut faire 120 requêtes par minute. Au-delà, les appels répondent 429 jusqu’à la fin de la minute ; attendez quelques secondes et réessayez. Regroupez vos lectures avec limit=250 plutôt que de lire les pièces une par une.
Nouvelles tentatives et idempotence
Les erreurs réseau arrivent. GET, PUT et DELETE peuvent être relancés sans risque. Avant de relancer un POST qui crée un document, vérifiez s’il existe déjà (par exemple grâce à votre référence enregistrée dans son mémo) pour qu’un délai dépassé ne crée jamais deux factures. Les pièces comptables sont numérotées en continu : un doublon s’annule, il ne se supprime pas.
Webhooks
Dans Paramètres → API, ajoutez une adresse HTTPS et choisissez les événements qu’elle reçoit. Chaque envoi est un POST avec un corps JSON et ces en-têtes :
x-balancelyne-topic: le nom de l’événement.x-balancelyne-delivery: un identifiant d’envoi unique ; ignorez un envoi déjà traité.x-balancelyne-hmac-sha256: le HMAC-SHA256 hexadécimal du corps brut, avec le secretwhsec_…du webhook comme clé.
Répondez par un 2xx en moins de 10 secondes. Les autres réponses et les délais dépassés sont relancés jusqu’à 5 fois, après 1, 2, 4 puis 8 minutes. Les derniers envois et leur statut s’affichent sous chaque webhook, avec un bouton d’envoi de test.
{
"event": "invoice.paid",
"company": { "id": "cm3…", "handle": "atlas-sarl", "name": "Atlas SARL" },
"sentAt": "2026-11-13T09:42:07.512Z",
"data": { "id": "cm3…", "number": "FAC-2026-0042", "total": 1191000, "balance": 0, "currency": "TND" }
}Vérifiez la signature avant de faire confiance au corps :
import { createHmac, timingSafeEqual } from "node:crypto";
// raw = the request body exactly as received (a string or Buffer), before JSON.parse
export function verify(raw: string, header: string, secret: string) {
const expected = createHmac("sha256", secret).update(raw).digest("hex");
const a = Buffer.from(expected), b = Buffer.from(header ?? "");
return a.length === b.length && timingSafeEqual(a, b);
}| Événement | Quand |
|---|---|
documents/create | Un document de vente ou d'achat a été créé. |
documents/update | Un document a été modifié. |
documents/delete | Un document a été supprimé. |
documents/void | Un document a été annulé. |
documents/sent | Un document a été envoyé par e-mail. |
invoices/create | Une facture a été créée. |
invoices/update | Une facture a été modifiée. |
estimates/accepted | Un devis a été accepté. |
estimates/declined | Un devis a été refusé. |
payments/create | Un paiement a été enregistré. |
payments/update | Un paiement a été modifié. |
payments/delete | Un paiement a été supprimé. |
customers/create | Un client a été ajouté. |
customers/update | Un client a été modifié. |
vendors/create | Un fournisseur a été ajouté. |
vendors/update | Un fournisseur a été modifié. |
products/create | Un produit ou service a été ajouté. |
products/update | Un produit ou service a été modifié. |
products/delete | Un produit ou service a été supprimé. |
journal/create | Une écriture manuelle a été passée. |
bank/imported | Des lignes bancaires ont été importées d'un relevé. |
payroll/approved | Une paie a été validée. |
imports/completed | Un import de données (QuickBooks, tableur) est terminé. |
Ressources
Chaque écriture suit les mêmes règles que l’application : contrôles, numérotation, passation au grand livre, date de clôture, limites de l’offre, piste d’audit et webhooks. Après une création ou une modification, l’objet revient sous la forme { "data": { … } }.
PUT (ou PATCH) ne change que les champs envoyés ; envoyer lines ou applications les remplace toutes.
Filtres
page,limit: pagination (voir plus haut).updated_since=2026-11-01T00:00:00Z: enregistrements modifiés depuis (paiements : créés depuis).from=2026-01-01&to=2026-03-31: période sur la date comptable (documents, paiements, journal).contact_id=…: documents, paiements ou écritures d’un client ou fournisseur.q=: recherche sur les noms, numéros, références.
Société et listes
Des listes en lecture seule pour trouver les identifiants dont vos documents ont besoin (codes de taxe, conditions, modes de paiement…).
| HTTP | Point d’accès |
|---|---|
| GET | /company |
| GET | /tax-codes |
| GET | /tax-rates |
| GET | /withholding-rates |
| GET | /payment-terms |
| GET | /payment-methods |
| GET | /classes |
| GET | /locations |
| GET | /warehouses |
curl https://balancelyne.slimbennasrallah.com/api/v1/tax-codes -H "Authorization: Bearer bal_…"Comptes
Le plan comptable (SCE tunisien). type vaut asset, liability, equity, income ou expense ; detailType détermine le comportement (bank, receivable, payable, tax_payable…). Les écritures demandent le rôle comptable. Les listes ajoutent le balance (signe naturel).
| HTTP | Point d’accès |
|---|---|
| GET | /accounts |
| GET | /accounts/:id |
| POST | /accounts |
| PUT | /accounts/:id |
| DELETE | /accounts/:id |
curl "https://balancelyne.slimbennasrallah.com/api/v1/accounts?type=expense&q=loyer" -H "Authorization: Bearer bal_…"
curl -X POST https://balancelyne.slimbennasrallah.com/api/v1/accounts -H "Authorization: Bearer bal_…" -H "Content-Type: application/json" \
-d '{ "code": "6132", "name": "Loyer dépôt", "type": "expense", "detailType": "expense" }'Clients et fournisseurs
/customers et /vendors sont des vues de /contacts (un tiers peut être les deux). Les listes ajoutent balance.receivable, balance.payable et les montants échus. Les téléphones sont enregistrés au format +216 XX XXX XXX ; taxId est le matricule fiscal.
| HTTP | Point d’accès |
|---|---|
| GET | /customers |
| GET | /customers/:id |
| POST | /customers |
| PUT | /customers/:id |
| DELETE | /customers/:id |
| GET | /vendors |
| GET | /vendors/:id |
| POST | /vendors |
| PUT | /vendors/:id |
| DELETE | /vendors/:id |
| GET | /contacts?type=customer|vendor |
curl "https://balancelyne.slimbennasrallah.com/api/v1/customers?q=alpha&updated_since=2026-11-01T00:00:00Z" -H "Authorization: Bearer bal_…"
curl -X POST https://balancelyne.slimbennasrallah.com/api/v1/customers -H "Authorization: Bearer bal_…" -H "Content-Type: application/json" \
-d '{ "displayName": "Société Alpha SARL", "email": "compta@alpha.tn", "phone": "71 123 456",
"taxId": "1234567/A/M/000", "billingAddress": { "address1": "12 rue de Rome", "city": "Tunis", "governorate": "TUN" } }'
curl -X PUT https://balancelyne.slimbennasrallah.com/api/v1/customers/CUSTOMER_ID -H "Authorization: Bearer bal_…" -H "Content-Type: application/json" -d '{ "notes": "Paie à 60 jours" }'Produits et services
type : service, inventory, non_inventory, bundle (les lots demandent components). Les prix sont en millimes. À la création, un produit stocké peut recevoir une quantité d’ouverture : initial: { qty, date, unitCost }.
| HTTP | Point d’accès |
|---|---|
| GET | /items |
| GET | /items/:id |
| POST | /items |
| PUT | /items/:id |
| DELETE | /items/:id |
curl -X POST https://balancelyne.slimbennasrallah.com/api/v1/items -H "Authorization: Bearer bal_…" -H "Content-Type: application/json" \
-d '{ "type": "service", "name": "Conseil", "sku": "CONS", "salesPrice": 120000, "salesTaxCodeId": "TAX_CODE_ID" }'Factures, devis, factures fournisseurs, dépenses
Chaque document de vente ou d’achat est une transaction avec des lines. Les lignes de vente prennent un itemId ; les lignes d’achat un itemId ou un accountId (catégorie). taxCodeId par ligne, timbre (1000 = 1 DT) sur les factures. Les totaux, la TVA, le FODEC et l’écriture sont calculés par Balancelyne. draft: true enregistre sans comptabiliser. Lisez un document par son id, ou par son numéro sur le chemin de son type (/invoices/FAC-2026-0042).
Chemins par type : /invoices, /estimates, /sales-receipts, /credit-notes, /refund-receipts, /delayed-charges, /purchase-orders, /bills, /vendor-credits, /expenses, /cheques, /inventory-adjustments, ou /transactions?type=invoice,bill. Filtre status : draft, open, partial, paid, void, unpaid, overdue…
| HTTP | Point d’accès |
|---|---|
| GET | /invoices |
| GET | /invoices/:id |
| POST | /invoices |
| PUT | /invoices/:id |
| DELETE | /invoices/:id |
| POST | /invoices/:id/void |
| GET | /transactions?type=…&status=…&contact_id=…&from=…&to=… |
curl "https://balancelyne.slimbennasrallah.com/api/v1/invoices?status=overdue" -H "Authorization: Bearer bal_…"
curl -X POST https://balancelyne.slimbennasrallah.com/api/v1/invoices -H "Authorization: Bearer bal_…" -H "Content-Type: application/json" \
-d '{ "contactId": "CUSTOMER_ID", "date": "2026-11-03", "timbre": 1000,
"lines": [{ "itemId": "ITEM_ID", "qty": 10, "rate": 150000, "taxCodeId": "TAX_CODE_ID" }] }'
curl -X POST https://balancelyne.slimbennasrallah.com/api/v1/bills -H "Authorization: Bearer bal_…" -H "Content-Type: application/json" \
-d '{ "contactId": "VENDOR_ID", "date": "2026-11-05", "reference": "STEG-11",
"lines": [{ "accountId": "ACCOUNT_ID", "qty": 1, "rate": 250000, "taxCodeId": "TAX_CODE_ID" }] }'
curl -X POST https://balancelyne.slimbennasrallah.com/api/v1/invoices/INVOICE_ID/void -H "Authorization: Bearer bal_…"Un document avec des paiements imputés ne peut pas être supprimé (409 has_payments) : supprimez ou modifiez d’abord le paiement, ou annulez le document. Dans une période close, ajoutez ?closing_password= sinon l’appel répond 409 period_closed.
Paiements
kind : received (d’un client), made (à un fournisseur), customer_refund, vendor_refund. applications indique les factures, factures fournisseurs ou avoirs réglés. Retenue à la source : withholding (millimes) et withholdingRateId ; amount est l’argent réellement versé. Sans accountId, un encaissement attend dans Valeurs à l’encaissement.
| HTTP | Point d’accès |
|---|---|
| GET | /payments |
| GET | /payments/:id |
| POST | /payments |
| PUT | /payments/:id |
| DELETE | /payments/:id |
| POST | /payments/:id/void |
curl -X POST https://balancelyne.slimbennasrallah.com/api/v1/payments -H "Authorization: Bearer bal_…" -H "Content-Type: application/json" \
-d '{ "kind": "received", "contactId": "CUSTOMER_ID", "date": "2026-11-20", "accountId": "BANK_ACCOUNT_ID",
"amount": 1763500, "withholding": 22500, "withholdingRateId": "RATE_ID",
"applications": [{ "transactionId": "INVOICE_ID", "amount": 1786000 }] }'Écritures
Écritures manuelles (sourceType: manual) par leur key. Chaque ligne a un debit ou un credit, un accountId, et un contactId sur les comptes clients et fournisseurs. Les débits doivent égaler les crédits. GET /journal-entries?source=all liste aussi les écritures des documents, paiements, paies… (lecture seule).
| HTTP | Point d’accès |
|---|---|
| GET | /journal-entries |
| GET | /journal-entries/:id |
| POST | /journal-entries |
| PUT | /journal-entries/:id |
| DELETE | /journal-entries/:id |
curl -X POST https://balancelyne.slimbennasrallah.com/api/v1/journal-entries -H "Authorization: Bearer bal_…" -H "Content-Type: application/json" \
-d '{ "date": "2026-11-30", "memo": "Apport en caisse",
"lines": [{ "accountId": "CASH_ID", "debit": 5000000 }, { "accountId": "CAPITAL_ID", "credit": 5000000 }] }'États
Tous les états de l’application : GET /reports donne les clés. Paramètres : from, to (ou range=this_year, last_month…), basis=accrual|cash, columns=month|quarter|class…, lang=fr|en|ar. Les montants des lignes sont en millimes.
| HTTP | Point d’accès |
|---|---|
| GET | /reports |
| GET | /reports/profit-and-loss |
| GET | /reports/balance-sheet |
| GET | /reports/trial-balance |
| GET | /reports/:key |
curl "https://balancelyne.slimbennasrallah.com/api/v1/reports/profit-and-loss?from=2026-01-01&to=2026-12-31&columns=month" -H "Authorization: Bearer bal_…"
curl "https://balancelyne.slimbennasrallah.com/api/v1/reports/balance-sheet?to=2026-12-31&lang=fr" -H "Authorization: Bearer bal_…"