Aller au contenu principal

Journaux comptables

Un journal comptable (accounting_ledger) porte le code sous lequel votre logiciel de comptabilité classe les écritures : VE pour les ventes, HA pour les achats, BQ pour la banque. Chaque journal appartient à une entreprise du workspace et n'est visible que d'elle. Les fiches clients et fournisseurs s'y rattachent par accounting_ledger_id (Clients et fournisseurs) : c'est ce rattachement qui rend le paramétrage comptable d'une fiche exploitable. Les endpoints de cette page ne touchent que les données de votre workspace et n'envoient rien vers l'extérieur - ni PPF (Portail Public de Facturation), ni Peppol.

Ce que Scribee fait pour vous​

  • Applique l'unicité du name et du code au sein d'une même entreprise : deux entreprises du workspace peuvent porter le même code de journal, une même entreprise non.
  • Fixe le journal à son entreprise : company_id est obligatoire à la création puis ignoré en mise à jour, et un journal ne change jamais d'entreprise.
  • Refuse la suppression d'un journal encore référencé, plutôt que de casser silencieusement les rattachements en place.
  • Trie la liste par code croissant, sans paramètre de tri à fournir.

Les endpoints​

  • GET / POST /api/v1/workspaces/{workspace_id}/accounting_ledgers - lister et créer des journaux
  • GET / PATCH / DELETE /api/v1/accounting_ledgers/{id} - lire, modifier, supprimer un journal

Comme pour les catégories (Catégories), seuls la liste et la création sont adressées par workspace. GET, PATCH et DELETE /api/v1/accounting_ledgers/{id} n'ont pas de workspace_id dans le chemin : l'identifiant est résolu sur l'ensemble des workspaces rattachés à votre client OAuth.

Un journal porte six champs, tous présents dans chaque réponse : id, company_id, code, name, created_at et updated_at. Il n'y a pas de paramètre include sur cette ressource.

Étape 1 : créer un journal​

Cet appel crée un journal dans votre workspace de production - il n'y a pas de sandbox. Il n'envoie rien vers l'extérieur et se défait avec le DELETE de l'étape 5. Tous les champs vont sous une clé englobante accounting_ledger : un corps envoyé sans elle retourne 400. Le scope requis est write : read n'est exigé sur aucune écriture de cette page.

name, code et company_id sont les trois champs attendus. name est plafonné à 255 caractères, code à 50.

curl -X POST https://app.scribee.tech/api/v1/workspaces/YOUR_WORKSPACE_ID/accounting_ledgers \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"accounting_ledger": {
"name": "Ventes",
"code": "VE",
"company_id": 1
}
}'

Réponse 201 :

{
"data": {
"id": 12,
"company_id": 1,
"code": "VE",
"name": "Ventes",
"created_at": "2026-07-31T11:15:00+02:00",
"updated_at": "2026-07-31T11:15:00+02:00"
}
}

Les horodatages sont sérialisés en ISO 8601 avec le décalage du fuseau Europe/Paris (+02:00 en heure d'été, +01:00 en heure d'hiver).

company_id désigne une entreprise du workspace du chemin (Entreprises et établissements). Omis, il retourne 422 ; s'il désigne une entreprise d'un autre workspace, l'appel retourne 404. Contrairement aux fiches clients et fournisseurs, il n'y a pas d'entreprise retenue par défaut.

Étape 2 : lister et retrouver un journal​

GET /api/v1/workspaces/{workspace_id}/accounting_ledgers retourne les journaux de toutes les entreprises du workspace, triés par code croissant et paginés (page, per_page - 20 par défaut, 100 au maximum). Le scope read suffit. L'enveloppe data + meta suit Conventions de l'API.

Un seul filtre est disponible : company_id, qui restreint la liste à une entreprise. Porté par une valeur non vide, il n'est jamais ignoré - une valeur qui ne désigne aucune entreprise du workspace renvoie une liste vide en 200, pas la liste complète et pas une erreur. Envoyé vide (?company_id=), en revanche, il est ignoré : la réponse porte alors tous les journaux du workspace, sans aucune erreur. C'est la forme que produit une variable de gabarit non substituée, et elle élargit silencieusement le résultat au lieu de le restreindre - omettez le paramètre plutôt que de l'envoyer vide. Il n'y a ni sort_by, ni sort_order, ni recherche par nom ou par code.

curl "https://app.scribee.tech/api/v1/workspaces/YOUR_WORKSPACE_ID/accounting_ledgers?company_id=1" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
{
"data": [
{
"id": 12,
"company_id": 1,
"code": "VE",
"name": "Ventes",
"created_at": "2026-07-31T11:15:00+02:00",
"updated_at": "2026-07-31T11:15:00+02:00"
}
],
"meta": {
"current_page": 1,
"per_page": 20,
"total_pages": 1,
"total_count": 1
}
}

Un journal seul se lit sur GET /api/v1/accounting_ledgers/{id}.

Étape 3 : rattacher un tiers à un journal​

Le rattachement passe par les endpoints de la fiche, pas par ceux des journaux : accounting_ledger_id est accepté à la création et à la mise à jour des clients et des fournisseurs. Le journal doit appartenir à la même entreprise que la fiche - un journal d'une autre entreprise, même du même workspace, est refusé par un 422 portant le message "doit exister", indiscernable de la réponse à un identifiant inexistant.

curl -X PATCH https://app.scribee.tech/api/v1/customers/42 \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"customer": {
"accounting_ledger_id": 12,
"auxiliary_account_number": "411AUX001"
}
}'

Le journal n'est qu'une des trois pièces du paramétrage comptable d'une fiche ; les deux autres sont auxiliary_account_number et les comptes de contrepartie (Clients et fournisseurs).

Étape 4 : renommer ou recoder​

PATCH porte sur name et code, tous deux optionnels : envoyez les champs à changer. company_id est accepté puis ignoré - un journal ne change jamais d'entreprise. Le scope requis est write.

curl -X PATCH https://app.scribee.tech/api/v1/accounting_ledgers/12 \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"accounting_ledger": {
"name": "Ventes France",
"code": "VE1"
}
}'

Réponse 200 avec le journal mis à jour. Les fiches déjà rattachées gardent leur accounting_ledger_id : renommer ou recoder un journal ne détache rien.

Étape 5 : supprimer un journal​

DELETE est une suppression définitive, pas un archivage. Le scope requis est destroy ou write : l'un des deux suffit, un token qui ne porte que write supprime donc aussi.

curl -X DELETE https://app.scribee.tech/api/v1/accounting_ledgers/12 \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Réponse 204 sans corps. La suppression est refusée tant qu'un enregistrement renvoie encore au journal - une fiche client ou fournisseur, un compte bancaire, ou une écriture comptable enregistrée. Détachez ces enregistrements d'abord, puis rejouez la suppression.

Ce qui se passe ensuite​

  • Rien ne part vers le PPF ni vers le réseau Peppol : créer, modifier ou supprimer un journal ne touche aucun document réglementaire, ni aucune facture déjà émise.
  • Le accounting_setup_complete des fiches rattachées suit le rattachement : il ne passe à true qu'une fois le journal, le compte auxiliaire et au moins un compte de contrepartie renseignés (Clients et fournisseurs).
  • Le accounting_setup_complete peut aussi passer à true en dehors de vos appels. Quand un compte de charge ou un compte de produit par défaut est déclaré depuis l'interface Scribee (ce paramètre ne se pose pas par l'API, et il se déclare aussi bien sur la connexion de l'entreprise à son logiciel de comptabilité, qui l'emporte, que sur le workspace, qui ne sert que de socle), la génération d'une écriture comptable pour une fiche qui ne porte aucun compte de contrepartie en crée un sur cette fiche, ce qui complète son paramétrage sans appel de votre part. Ne vous appuyez donc pas sur un accounting_setup_complete à false comme sur un état stable (Clients et fournisseurs).
  • La liste des fiches accepte le filtre accounting_setup_status pour retrouver celles dont le paramétrage est encore incomplet.
  • Un journal peut apparaître ou changer en dehors de vos appels. Quand son entreprise est reliée à un logiciel de comptabilité depuis l'interface Scribee, la synchronisation de ce logiciel réécrit le name des journaux qu'elle retrouve et crée ceux qu'elle ne retrouve pas. Elle retrouve un journal par son code, et à défaut par l'identifiant que ce même logiciel lui avait attribué lors d'une synchronisation antérieure : un journal recodé côté logiciel est donc retrouvé par cet identifiant et son name réécrit, alors que son code reste celui d'avant - le code d'un journal existant n'est jamais modifié, y compris dans ce cas, et le journal conserve donc un code que le logiciel n'utilise plus. La création, elle, n'est pas systématique : un code rapporté qui ne diffère d'un code déjà enregistré dans la même entreprise que par la casse (bq face à BQ) est refusé, rapporté en erreur par la synchronisation, et le journal correspondant n'apparaît jamais. Comme name reste unique au sein de l'entreprise, un libellé déjà porté par un autre journal de la même entreprise est enregistré suivi du code entre parenthèses : un second journal libellé Banque, de code BQ10, est enregistré Banque (BQ10). Si cette forme est elle aussi déjà prise, un numéro s'ajoute dans les parenthèses, à partir de 2 : Banque (BQ10 2), puis Banque (BQ10 3), et ainsi de suite jusqu'à 99 ; au-delà, le journal est rejeté et la synchronisation le rapporte en erreur. Ne vous appuyez donc pas sur la forme exacte du libellé enregistré : le name que vous relisez n'est pas toujours le libellé du logiciel - identifiez un journal par son id ou son code, pas par son libellé.

Erreurs et cas limites​

400 Bad Request​

Trois causes :

  • un corps de requête sans la clé englobante accounting_ledger, ou avec un objet accounting_ledger vide, n'atteint jamais la validation du modèle : la lecture des paramètres échoue avant, et la réponse est un 400 dans l'enveloppe {error, message} habituelle, avec error à bad_request et le message "Le corps de la requête est manquant ou mal formé" ;
  • sur la liste, un page qui n'est pas un entier supérieur ou égal à 1 : 0, une valeur négative, une valeur vide, une valeur non numérique, ou un page envoyé comme tableau ou comme objet (page[]=1) ;
  • sur la liste, demander une page au-delà de la dernière page d'une collection non vide.

Un page mal formé retourne :

{
"error": "bad_request",
"message": "Le numéro de page doit être un entier supérieur ou égal à 1"
}

Le dépassement de la dernière page retourne :

{
"error": "bad_request",
"message": "Le numéro de page dépasse le nombre de pages disponibles"
}

Un per_page mal formé ne produit pas de 400 : il retombe silencieusement sur la valeur par défaut.

422 : validation échouée​

Les erreurs de validation des journaux sont toutes regroupées sous details.base, avec le code validation_failed. Un name ou un code déjà utilisé par la même entreprise :

{
"error": "unprocessable_entity",
"code": "validation_failed",
"message": "La validation a échoué",
"details": {
"base": ["Name a déjà été pris"]
}
}

Le même corps porte "Code a déjà été pris" quand c'est le code qui est en cause, et "Name doit être rempli(e)" ou "Code doit être rempli(e)" quand le champ est vide. Une création sans company_id retourne :

{
"error": "unprocessable_entity",
"code": "validation_failed",
"message": "La validation a échoué",
"details": {
"base": ["L'entreprise est requise"]
}
}

Réutilisez le journal existant (étape 2) ou choisissez un autre couple name / code.

422 : journal encore référencé​

DELETE sur un journal qu'un enregistrement référence encore retourne un 422 portant le code dependent_records. Ce corps ne porte pas de clé details, contrairement au 422 de validation. Une fiche client ou fournisseur rattachée retourne :

{
"error": "unprocessable_entity",
"code": "dependent_records",
"message": "Impossible de supprimer un journal comptable avec des tiers associés."
}

Un compte bancaire ou une écriture comptable qui bloque la suppression retourne le même code avec un message plus général :

{
"error": "unprocessable_entity",
"code": "dependent_records",
"message": "Échec de la suppression du journal comptable."
}

Branchez-vous sur le code plutôt que sur le texte. Les fiches se détachent en envoyant accounting_ledger_id: null sur la fiche ; les comptes bancaires et les écritures comptables se traitent depuis l'interface Scribee.

404 Not Found​

{
"error": "not_found",
"message": "La ressource demandée est introuvable"
}

Les causes, indiscernables les unes des autres dans la réponse :

  • le journal n'existe pas ;
  • le journal appartient à un workspace hors du périmètre de votre application ;
  • sur GET, PATCH et DELETE /api/v1/accounting_ledgers/{id}, le journal appartient à un workspace dont l'allowlist d'adresses IP refuse l'adresse appelante ;
  • le company_id passé à la création ne désigne pas une entreprise du workspace du chemin.

403 Forbidden​

{
"error": "forbidden",
"message": "Vous n'êtes pas autorisé à effectuer cette action"
}

Les scopes exigés : read pour les deux GET, write pour POST et PATCH, destroy ou write pour DELETE. Sur les chemins préfixés par {workspace_id}, un workspace non rattaché à votre client OAuth retourne "L'application n'a pas accès à cet espace de travail", et un workspace dont l'allowlist d'adresses IP refuse l'adresse appelante retourne "Cette adresse IP n'est pas autorisée pour cet espace de travail". Sur /api/v1/accounting_ledgers/{id}, ce second refus se présente en 404.

401 Unauthorized​

Token absent, expiré ou révoqué ; le corps de la réponse est vide. Demandez un nouveau token (Authentification).

Pages liées​