Aller au contenu principal

Recevoir les factures fournisseurs

Au 1er septembre 2026, toute entreprise assujettie à la TVA en France doit être en mesure de recevoir des factures électroniques : la réception est la première obligation de la réforme, avant même l'émission. Les factures d'achat de vos entreprises sont enregistrées dans Scribee, votre système les lit par l'API, puis pilote les statuts côté acheteur - mise à disposition, approbation, litige, refus, paiement. Une facture auto-facturée, établie par votre client en votre nom et reçue par le réseau Peppol, fait exception : elle est enregistrée en vente (voir l'étape 1). Cette page couvre les deux appels qui portent ce flux : la liste des factures et la transition de cycle de vie.

Ce que Scribee fait pour vous​

  • Canal d'origine tracé : chaque facture enregistrée porte le canal par lequel elle est entrée dans le workspace, dans le champ upload_source :
    • api : fichier déposé sur l'endpoint d'import par l'API.
    • email : facture reçue par email.
    • supplier_portal : dépôt par le fournisseur sur son portail.
    • chorus : facture reçue de Chorus Pro, le portail de facturation de la sphère publique ; elle est enregistrée en achat.
    • manual : aucun de ces canaux. Une facture construite champ par champ sur POST /api/v1/workspaces/{workspace_id}/invoices porte manual, tout comme une facture reçue par le réseau Peppol.
  • Cycle de vie AIFE (Agence pour l'informatique financière de l'État) : chaque changement de statut est un évènement horodaté et auditable, avec son motif normalisé et, pour un message venu du réseau, le rôle de la partie émettrice ainsi que l'identifiant de la plateforme destinataire retenue, consultables via include=lifecycle_events.
  • Notifications : des Webhooks poussent vers votre système l'arrivée d'une facture (invoice.created) et chaque changement de statut (invoice.lifecycle_event.created).

:::caution Le payload invoice.created est un instantané pris à la création Sur une facture issue d'un fichier (import par l'API, email, portail fournisseur), l'instantané est sérialisé avant que le canal d'origine ne soit enregistré : le payload porte alors upload_source: "manual" quel que soit le canal réel. Ne vous fiez pas à ce champ dans le webhook - relisez la facture sur GET /api/v1/invoices/{id} pour sa valeur définitive. La facture y est par ailleurs encore à l'état draft, donc lifecycle_available_transitions ne liste que les transitions ouvertes depuis cet état. :::

Le parcours d'une facture reçue​

Une réception Peppol sans le SIREN de l'acheteur est refusée​

Une facture qui vous arrive par le réseau Peppol, émise par un fournisseur établi en France, est refusée quand l'acheteur n'y déclare pas son identifiant légal (BT-47). Le refus intervient avant toute écriture : aucune facture n'est créée, rien n'entre dans le workspace, et ni la liste ni les webhooks n'en portent trace. La règle porte l'identifiant SCRIBEE-BR-FR-11. Elle ne vise que cette réception : une facture que vous créez, importez ou déposez par l'API n'y est jamais soumise.

Ce que la facture doit porter, c'est le SIREN de l'acheteur dans son identifiant légal, sous le schéma 0002 et composé exactement de 9 chiffres : en UBL, cac:AccountingCustomerParty/cac:Party/cac:PartyLegalEntity/cbc:CompanyID avec schemeID="0002" ; en CII, y compris le CII embarqué dans un Factur-X, ram:BuyerTradeParty/ram:SpecifiedLegalOrganization/ram:ID sous le même schéma.

Un SIREN lisible ailleurs ne satisfait pas la règle. Un acheteur identifié seulement par son numéro de TVA intracommunautaire (BT-48, FR69572053833) ou seulement par son adresse électronique (BT-49, schéma 0225) est refusé, alors même que les neuf chiffres de son SIREN figurent dans ces valeurs. C'est une décision prise en connaissance de ce qu'elle rejette, pas un oubli : la norme AFNOR XP Z12-012, Annexe A, rend le SIREN de l'acheteur obligatoire pour les factures relevant du périmètre e-invoicing, et elle le rend obligatoire en BT-47.

Un fournisseur établi hors de France n'est pas concerné. Sa facture vers un acheteur français est une acquisition intracommunautaire, hors du périmètre e-invoicing ; elle est reçue normalement. Scribee lit l'établissement du vendeur sur les identifiants que la facture lui donne, dans cet ordre : une immatriculation légale sous un schéma français (0002 SIREN ou 0009 SIRET) qui se réduit à un SIREN le désigne comme français ; une immatriculation légale sous un schéma étranger le désigne comme étranger, même quand il porte par ailleurs un numéro de TVA français ; en l'absence de toute immatriculation légale, c'est le numéro de TVA qui répond.

Ce que vous avez à faire : demandez à vos fournisseurs français de renseigner le SIREN de l'acheteur en BT-47. Le porter dans le numéro de TVA ou dans l'adresse électronique ne suffira pas.

Une réception Peppol adressée à une autre entreprise est refusée​

Une facture reçue par le réseau Peppol est aussi refusée quand son destinataire - l'acheteur, ou le vendeur sur une facture auto-facturée - contredit le participant Peppol auquel elle a été envoyée. Seule une contradiction déclarée compte : la facture est refusée quand elle porte, pour ce destinataire, une adresse électronique ou un identifiant légal sous le même schéma que l'identifiant Peppol du participant, et qu'aucune de ces valeurs n'est la sienne. Un identifiant absent, ou déclaré sous un autre schéma, ne fait pas refuser la facture.

Le refus intervient avant toute écriture : aucune facture n'est créée, aucun webhook n'est émis, aucun évènement de cycle de vie n'est enregistré. C'est la plateforme émettrice qui en est informée, par le statut 221 Erreur de routage.

Étape 1 : détecter une nouvelle facture fournisseur​

Deux moyens : les Webhooks (l'évènement invoice.created pousse la facture dès son enregistrement), ou l'interrogation périodique de la liste. La liste retourne les factures des deux sens - direction vaut purchases (Achat) ou sales (Vente) sur chaque élément. Les factures d'achat sont toujours retournées ; les factures de vente ne le sont que pour les entreprises dont l'espace de travail couvre la vente, sans quoi elles sont absentes de la liste sans erreur - sauf les factures auto-facturées reçues par Peppol, décrites plus bas. Elle accepte, en plus de la pagination (page, per_page), du tri (sort_by, sort_order) et d'include, six filtres : created_at_from, created_at_to, updated_at_from, updated_at_to, lifecycle_status et company_ids (tableau). lifecycle_status attend le nom d'état, pas le code numérique : draft, deposited, received, available, taken_in_charge, approved, disputed, refused, payment_sent, collected, rejected ou cancelled - un nom seul ou un tableau de noms. Toute autre valeur, y compris un code comme 203, répond 400 avec "Valeur(s) lifecycle_status invalide(s). Valeurs autorisées : ...". Pour détecter les arrivées, triez par date de création décroissante et arrêtez-vous au premier identifiant déjà connu. Cet appel est une lecture : aucun effet de bord, rejouable à volonté.

curl "https://app.scribee.tech/api/v1/workspaces/YOUR_WORKSPACE_ID/invoices?sort_by=created_at&sort_order=desc" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Réponse abrégée aux champs utiles à un flux achats :

{
"data": [
{
"id": 12401,
"invoice_number": "FAC-2026-0341",
"issue_date": "2026-07-21",
"due_date": "2026-08-20",
"direction": "purchases",
"type_code": "invoice",
"proforma": false,
"upload_source": "api",
"seller": { "party_id": 87, "name": "Fournitures Pro SARL" },
"tax_inclusive_amount": 1770.0,
"lifecycle_state": "available",
"lifecycle_status_code": "203",
"lifecycle_available_transitions": ["take_in_charge", "approve", "dispute", "refuse", "send_payment", "revert_to_draft"]
},
{
"id": 12398,
"invoice_number": "INV-2026-00212",
"direction": "sales",
"lifecycle_state": "deposited",
"lifecycle_status_code": "200"
}
],
"meta": { "current_page": 1, "per_page": 20, "total_pages": 8, "total_count": 156 }
}

Sur une facture d'achat, le fournisseur est la partie seller. lifecycle_available_transitions liste les évènements que votre système peut déclencher depuis l'état courant : lisez-le avant chaque transition plutôt que de recalculer la machine à états de votre côté. Le détail d'une facture, lignes comprises, se lit sur GET /api/v1/invoices/{id} avec le même paramètre include (Conventions de l'API).

Une facture auto-facturée (type_code en self_billed_*, codes BT-3 389, 501, 500, 471, 473, 261 et 502) est établie par votre client en votre nom. Reçue par le réseau Peppol, elle est enregistrée en vente : direction vaut sales, votre entreprise en est la partie seller, et la facture entre directement en 203 Mise à disposition, sans passer par 200 Déposée. Elle est retournée par la liste et lisible sur GET /api/v1/invoices/{id} même quand l'espace de travail de l'entreprise ne couvre pas la vente. Depuis 203, la seule transition ouverte est collect (voir Le cycle de vie d'une facture). Les autres factures reçues par Peppol restent des factures d'achat.

:::caution Une facture proforma n'est pas une facture Quand Scribee reconnaît, à la lecture d'un document déposé en achat, une facture proforma de votre fournisseur, il la conserve en achat avec proforma à true. Ce n'est pas une facture : Scribee n'en génère aucune écriture comptable, ne l'inclut dans aucun export comptable, et la facture définitive qui la remplace n'est pas traitée comme son doublon. Ne la comptabilisez pas et ne la payez pas comme une facture : c'est la facture définitive, déposée ensuite, qui fait foi. proforma vaut false sur toute autre facture et ne s'écrit pas par l'API. :::

Étape 2 : valider une facture importée (203 Mise à disposition)​

Une facture que vous importez, qui arrive par email ou qui est déposée sur le portail fournisseur démarre en 000 Brouillon : l'évènement make_available la fait entrer dans le cycle de vie, directement en 203 Mise à disposition - le statut 200 Déposée est propre au sens Vente. Sur une facture d'achat, make_available part de 000 Brouillon - le cas de vos imports - et aussi de 202 Reçue, l'état dans lequel la plateforme place une facture arrivée par le réseau réglementaire.

Cet appel engage la facture dans le cycle de vie réglementaire ; elle cesse d'être modifiable. Rien n'est envoyé au fournisseur. Si l'entreprise a connecté son logiciel comptable avec livraison automatique depuis l'interface Scribee, la facture validée y est transmise. Une facture importée peut revenir en brouillon via l'évènement revert_to_draft ; lisez lifecycle_available_transitions pour savoir si l'évènement est ouvert sur une facture donnée.

make_available est refusé tant que la facture porte une erreur d'import bloquante. C'est le cas d'un fichier importé auquel il manque un champ obligatoire - numéro de facture, date d'émission, type de document ou devise : l'import aboutit, la facture est créée en 000 Brouillon avec une valeur de remplacement dans le champ manquant, et la transition est ensuite refusée. Le message renvoyé est celui de la transition impossible (Impossible de passer de draft à make_available...), qui ne nomme pas cette cause, et l'API n'expose pas les erreurs d'import d'une facture. Corrigez la facture par PATCH /api/v1/invoices/{id} : une mise à jour réussie efface les erreurs d'import et débloque make_available.

curl -X PATCH https://app.scribee.tech/api/v1/invoices/YOUR_INVOICE_ID/transition \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "invoice": { "event": "make_available" } }'
{
"data": {
"lifecycle_state": "available",
"lifecycle_status_code": "203",
"lifecycle_available_transitions": ["take_in_charge", "approve", "dispute", "refuse", "send_payment", "revert_to_draft"]
}
}

Étape 3 : prendre en charge (204 Prise en charge) - facultatif​

La prise en charge signale que la facture est entrée dans votre circuit de traitement interne. Le statut est facultatif : vous pouvez approuver, contester ou refuser directement depuis 203. Il est enregistré dans Scribee et notifié par webhook. Même appel que ci-dessus avec "event": "take_in_charge" ; depuis 204, les transitions disponibles sont approve, dispute, refuse et send_payment.

Étape 4 : approuver (205 Approuvée)​

L'approbation est l'issue nominale après vérification de la facture. Elle se déclenche depuis 203, 204 ou 207, et ouvre la voie au paiement.

curl -X PATCH https://app.scribee.tech/api/v1/invoices/YOUR_INVOICE_ID/transition \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "invoice": { "event": "approve" } }'
{
"data": {
"lifecycle_state": "approved",
"lifecycle_status_code": "205",
"lifecycle_available_transitions": ["send_payment"]
}
}

Étape 5 : contester ou refuser (207 En litige, 210 Refusée)​

Un litige ou un refus concerne une facture réelle, sur votre compte de production, et laisse une trace permanente : le statut, son motif normalisé et son horodatage sont enregistrés dans l'historique auditable de la facture. L'un comme l'autre sont enregistrés dans Scribee et notifiés à votre système par webhook ; l'appel n'envoie rien au fournisseur. Les deux diffèrent par leur réversibilité : depuis 207, vous pouvez encore approuver ou refuser, tandis que le refus est définitif - aucune transition ne quitte l'état Refusée. Seule exception, hors API : un utilisateur de Scribee peut rouvrir depuis l'interface une facture d'achat dont le refus n'a jamais quitté Scribee ; elle repasse alors à available sans évènement de cycle de vie ni webhook (voir Rouvrir une facture d'achat refusée).

Les deux exigent un code motif normalisé (reason_code), propre à chaque statut ; la liste des codes valides par statut est sur Le cycle de vie d'une facture. Le texte libre reason (250 caractères au maximum) est optionnel, sauf pour les codes AUTRE et REF_ERR qui l'exigent.

curl -X PATCH https://app.scribee.tech/api/v1/invoices/YOUR_INVOICE_ID/transition \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"invoice": {
"event": "dispute",
"reason_code": "TX_TVA_ERR",
"reason": "Taux de TVA de la ligne 2 : 20 % attendu, 5,5 % facturé"
}
}'
{
"data": {
"lifecycle_state": "disputed",
"lifecycle_status_code": "207",
"lifecycle_available_transitions": ["approve", "refuse"]
}
}

Le refus suit la même forme, avec un code du jeu propre au statut 210 :

curl -X PATCH https://app.scribee.tech/api/v1/invoices/YOUR_INVOICE_ID/transition \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "invoice": { "event": "refuse", "reason_code": "DOUBLON" } }'
{
"data": {
"lifecycle_state": "refused",
"lifecycle_status_code": "210",
"lifecycle_available_transitions": []
}
}

Étape 6 : déclarer le paiement (211 Paiement transmis)​

Depuis 203 Mise à disposition, 204 Prise en charge ou 205 Approuvée, send_payment enregistre que le paiement a été émis vers le fournisseur. La prise en charge et l'approbation sont facultatives : vous pouvez déclarer le paiement d'une facture que vous n'avez pas approuvée. Sur un compte où le circuit d'approbation des factures d'achat est activé, en revanche, send_payment n'est proposé que depuis 205. L'encaissement (212 Encaissée) ne se déclenche pas par cet endpoint : il est posé par Scribee quand le montant réglé de la facture atteint le montant TTC - voir Les paiements.

curl -X PATCH https://app.scribee.tech/api/v1/invoices/YOUR_INVOICE_ID/transition \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "invoice": { "event": "send_payment" } }'
{
"data": {
"lifecycle_state": "payment_sent",
"lifecycle_status_code": "211",
"lifecycle_available_transitions": []
}
}

lifecycle_available_transitions est vide : la suite (212 Encaissée) est posée par Scribee à partir du montant réglé, pas par une transition directe.

Ce qui se passe ensuite​

  • Chaque transition crée un évènement de cycle de vie sur la facture : statut, libellé, date et motif, consultables via include=lifecycle_events sur la liste comme sur le détail. L'évènement n'identifie pas son auteur, et ses trois champs sender_* ne décrivent pas tous la même partie. Pour un message de statut reçu du réseau, sender_role reprend le rôle de la partie émettrice du message, tandis que sender_id et sender_scheme_id identifient la plateforme destinataire retenue (la partie destinataire de rôle WK) - pas l'émetteur. Les deux derniers valent null quand le message ne porte aucune partie destinataire de ce rôle. Les trois restent null pour une transition que vous déclenchez par l'API. C'est l'historique auditable de la réforme ; il ne s'efface pas.
  • Un webhook invoice.lifecycle_event.created est émis à chaque évènement - voir Webhooks.
  • lifecycle_available_transitions ne contient que les évènements que votre système peut déclencher. receive, reject et cancel n'y figurent jamais - mais le traitement des flux réglementaires entrants, lui, les applique : les statuts 202 Reçue, 213 Rejetée et 220 Annulée peuvent donc bel et bien apparaître dans l'historique, sans jamais avoir été proposés dans lifecycle_available_transitions. Traitez lifecycle_state comme une valeur ouverte, avec un cas par défaut pour un état inconnu.
  • Tous les statuts que vous déclenchez - prise en charge (204), approbation (205), litige (207), refus (210), paiement transmis (211) - sont enregistrés dans Scribee et notifiés par webhook.

Erreurs et cas limites​

Toutes les erreurs de transition partagent le format 422 : error vaut unprocessable_entity, code porte l'identifiant machine de la classe d'échec, message décrit la cause en français, et details reste vide sur une facture d'achat. Chaque cause a son propre message : un refus n'emprunte jamais le texte d'un autre. Branchez-vous sur le statut et sur code, pas sur le texte. Le format général des erreurs s'applique par ailleurs.

422 : évènement inconnu​

{
"error": "unprocessable_entity",
"code": "invalid_argument",
"message": "Évènement de cycle de vie inconnu ou manquant. Fournissez un nom d'évènement valide parmi les transitions disponibles de la facture.",
"details": {}
}

Le champ event est absent ou ne correspond à aucun évènement. Envoyez un des noms retournés dans lifecycle_available_transitions. La valeur doit être une chaîne de caractères : un nombre ou un objet JSON ne produit pas ce 422 mais une erreur serveur.

422 : transition impossible depuis l'état courant​

{
"error": "unprocessable_entity",
"code": "operation_failed",
"message": "Impossible de passer de refused à approve. L'état actuel ne permet pas cette transition.",
"details": {}
}

L'évènement existe mais l'état courant ne le permet pas - ici une approbation après refus, définitif. Relisez la facture et basez-vous sur lifecycle_available_transitions, qui fait foi.

Ce message ne parle que de l'état. Un contrôle métier qui bloque une transition pourtant permise depuis l'état courant a désormais son propre message : c'est le cas suivant.

422 : erreurs d'import bloquantes​

{
"error": "unprocessable_entity",
"code": "operation_failed",
"message": "La facture comporte des erreurs d'import bloquantes. Corrigez-les avant de changer son statut.",
"details": {}
}

make_available sur un brouillon d'achat reste refusé tant que la facture porte une erreur d'import bloquante - typiquement une facture entrée sans invoice_number, issue_date, type_code ou currency_code, dont Scribee a rempli le champ manquant par un placeholder. Un PATCH portant la facture entière efface ces erreurs et débloque la transition. Les deux autres contrôles de dépôt (conformité Factur-X du PDF fourni, mentions légales obligatoires) ne visent que les factures de vente et n'apparaissent jamais sur ce parcours - voir Le cycle de vie d'une facture.

422 : transition réservée au système​

{
"error": "unprocessable_entity",
"code": "operation_failed",
"message": "La transition cancel ne peut pas être déclenchée manuellement.",
"details": {}
}

receive, reject et cancel existent dans le moteur d'états, mais aucun appel de l'API ne peut les déclencher, quel que soit le sens de la facture ; les évènements du sens Vente (deposit, collect) sont refusés de la même façon sur une facture d'achat. Vous obtenez ce message quand l'état courant permettrait la transition, et le message de transition impossible ci-dessus sinon. Les évènements que vous pouvez déclencher côté achat : make_available, take_in_charge, approve, dispute, refuse, send_payment, revert_to_draft.

422 : motif manquant ou invalide​

{
"error": "unprocessable_entity",
"code": "operation_failed",
"message": "Un motif normalisé est requis pour le statut Refusée",
"details": {}
}

dispute et refuse exigent un reason_code. Deux variantes du même contrôle : un code hors du jeu du statut visé renvoie Le motif DEST_INC n'est pas autorisé pour le statut Refusée, et un code AUTRE ou REF_ERR sans texte libre renvoie Un commentaire est requis pour le motif AUTRE. La liste des codes par statut est sur Le cycle de vie d'une facture.

404 : facture introuvable​

L'identifiant n'existe pas, ou la facture appartient à un workspace hors du périmètre de votre application - les deux cas renvoient la même réponse, l'API ne révèle pas l'existence de ressources hors de votre périmètre (conventions).

403 : scope insuffisant​

La transition exige le scope write : le token doit le porter, et read write est la combinaison à demander. La lecture de la liste, elle, exige read. Redemandez un token avec le bon scope (Authentification).

Pages liées​