Lots de paiement
Un lot de paiement (payment_batch) regroupe des virements fournisseurs débités d'un même compte bancaire et approuvés ensemble. Chaque virement du lot est une instruction de paiement (payment_instruction) : un bénéficiaire, un montant, une date d'exécution.
Cette API prépare les lots - création d'un brouillon, modification, soumission à approbation, approbation ou refus -, remet un lot hosted_consent approuvé à son canal, génère le fichier SEPA d'un lot sepa_file approuvé, lit les lots et leurs instructions, et vous laisse rapprocher chaque instruction de l'opération bancaire qui l'a réglée. Aucune de ces opérations ne prouve qu'un virement a été exécuté : seuls l'état du lot et le statut de ses instructions en disent quelque chose.
Ce que cette surface publie
Vingt opérations :
| Verbe et chemin | Ce qu'elle fait |
|---|---|
GET /api/v1/workspaces/{workspace_id}/companies/{company_id}/payment_batches | Liste les lots de l'entreprise |
GET /api/v1/payment_batches/{id} | Lit un lot |
GET /api/v1/payment_batches/{id}/instructions | Liste les instructions d'un lot |
GET /api/v1/payment_instructions/{id} | Lit une instruction |
GET /api/v1/payment_batches/{id}/settlement | Lit le règlement des instructions d'un lot et ses suggestions |
GET /api/v1/payment_batches/{id}/settlement/candidates | Cherche les opérations bancaires qui ont pu régler une instruction, sur les dates de votre choix |
POST /api/v1/workspaces/{workspace_id}/companies/{company_id}/payment_batches | Crée un lot en brouillon |
PATCH /api/v1/payment_batches/{id} | Modifie un brouillon |
POST /api/v1/payment_batches/{id}/submit_for_approval | Soumet un brouillon à approbation |
POST /api/v1/payment_batches/{id}/approve | Approuve un lot |
POST /api/v1/payment_batches/{id}/refuse | Refuse l'approbation d'un lot |
POST /api/v1/payment_batches/{id}/submit | Remet un lot hosted_consent approuvé à son canal |
POST /api/v1/payment_batches/{id}/consent_session | Publie l'adresse de la page de consentement d'un lot hosted_consent remis |
POST /api/v1/payment_batches/{id}/settlement/suggestions/{suggestion_id}/dismiss | Écarte une suggestion |
POST /api/v1/payment_batches/{id}/settlement/suggestions/{suggestion_id}/confirm | Confirme une suggestion |
POST /api/v1/payment_batches/{id}/settlement/confirm | Confirme l'opération bancaire qui a réglé une instruction |
POST /api/v1/payment_batches/{id}/settlement/instructions/{payment_instruction_id}/undo | Annule le rapprochement d'une instruction |
POST /api/v1/payment_batches/{id}/settlement/instructions/{payment_instruction_id}/not_executed | Déclare non exécutée une instruction dont l'exécution est à confirmer |
POST /api/v1/payment_batches/{id}/sepa_export | Génère le fichier SEPA d'un lot |
GET /api/v1/payment_batches/{id}/sepa_export | Lit l'export d'un lot, ou télécharge son fichier |
Un token portant le scope read est requis sur les six premières. Toutes les autres exigent le scope write : les sept écritures sur les lots, les cinq opérations POST sur settlement et les deux opérations sur sepa_export, y compris leur GET.
Lister les lots d'une entreprise
curl "https://app.scribee.tech/api/v1/workspaces/YOUR_WORKSPACE_ID/companies/YOUR_COMPANY_ID/payment_batches?state=submitted&per_page=50" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Les lots sortent du plus récemment créé au plus ancien, à égalité de date de l'identifiant le plus grand au plus petit. La pagination est par décalage, avec page et per_page - 20 par défaut, 100 au maximum - et meta porte current_page, per_page, total_pages et total_count.
Cinq filtres, tous facultatifs et cumulables :
| Filtre | Valeurs | Ce qu'il retient |
|---|---|---|
state | une valeur de state | Les lots dans cet état |
channel | hosted_consent, sepa_file | Les lots remis par ce canal |
bank_account_id | un entier | Les lots débités de ce compte |
execution_date_from | une date AAAA-MM-JJ | Les lots dont l'execution_date est à cette date ou après |
execution_date_to | une date AAAA-MM-JJ | Les lots dont l'execution_date est à cette date ou avant |
Un filtre que nous ne savons pas appliquer rend une collection vide, jamais une erreur : une valeur de state ou de channel inconnue, un identifiant qui n'est pas un entier, une date dans un autre format que AAAA-MM-JJ. Un paramètre absent ou vide n'est pas un filtre. Un lot sans execution_date n'est retenu par aucun des deux filtres de date.
Lire un lot
curl https://app.scribee.tech/api/v1/payment_batches/7301 \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
{
"data": {
"id": 7301,
"company_id": 34,
"bank_account_id": 812,
"name": "Fournisseurs 2026-08",
"channel": "hosted_consent",
"state": "submitted",
"version": 6,
"instructions_count": 2,
"total_amount": 1250.5,
"currency_code": "EUR",
"execution_date": "2026-08-29",
"approved_at": "2026-08-27T10:02:11+02:00",
"submitted_at": "2026-08-27T10:05:40+02:00",
"progress": null,
"error_code": null,
"error_message": null,
"retryable": false,
"started_at": "2026-08-27T10:05:40+02:00",
"finished_at": "2026-08-27T10:05:43+02:00",
"submission_status": "accepted",
"submission_refused_by": null,
"verification_required": false,
"approved_by": {
"actor_type": "api_client",
"name": "Compta Connect",
"decided_at": "2026-08-27T10:02:11+02:00"
},
"refused_by": null,
"created_at": "2026-08-26T16:40:02+02:00",
"updated_at": "2026-08-27T10:05:43+02:00"
}
}
channel dit par où le lot quitte Scribee : hosted_consent, une demande de paiement validée par un consentement donné sur une page de la banque ; sepa_file, un fichier de virements SEPA produit par Scribee.
version change à chaque écriture du lot, y compris quand l'une de ses instructions est modifiée. Une exception : le passage d'une instruction à pending, settled ou rejected ne change pas version à lui seul ; seul le changement d'état du lot qui peut en découler le fait.
started_at porte la même valeur que submitted_at. progress vaut toujours null : rien ne mesure l'avancement d'une remise, et nous ne publions pas de pourcentage fabriqué.
Les états d'un lot
state | Ce qu'il signifie |
|---|---|
draft | Le lot est en préparation. Un lot dont l'approbation a été refusée revient ici |
pending_approval | Le lot attend la décision d'une personne habilitée à l'approuver |
approved | Le lot est approuvé. Sa remise n'a pas commencé, ou elle a commencé et son issue n'est pas encore connue |
submitted | Le lot a été remis à son canal. L'issue d'au moins une de ses instructions n'est pas connue |
completed | Chaque instruction du lot est settled |
partially_completed | Certaines instructions du lot sont settled et les autres rejected : le status de chaque instruction dit lesquelles |
rejected | Chaque instruction du lot est rejected. Cet état est définitif |
failed | La remise du lot a été refusée, par le prestataire de paiement ou par Scribee avant tout envoi : submission_refused_by dit lequel. Cet état est définitif |
Deux états sont définitifs : rejected et failed. completed et partially_completed n'ont qu'une sortie : l'annulation d'un règlement que seule une confirmation portait, qui ramène le lot à submitted (Annuler un règlement confirmé).
submitted ne prouve pas que les virements ont été exécutés. Il dit que le canal a pris le lot : pour hosted_consent, le canal a accepté la demande de paiement ; pour sepa_file, le fichier a été produit. Le lot ne passe à completed, partially_completed ou rejected que lorsque chacune de ses instructions a un statut définitif : tant que l'une d'elles est submitted ou pending, le lot reste submitted. Une instruction devient settled quand la banque signale son exécution, ou quand vous confirmez l'opération bancaire qui l'a réglée. Scribee ne reçoit pas de réponse de la banque sur un fichier SEPA : un lot sepa_file ne quitte submitted que par la confirmation du règlement de ses instructions, ou par la déclaration de non-exécution de celles dont l'exécution est à confirmer.
Une remise engagée dont l'issue n'est pas connue
Un lot approved dont submitted_at est renseigné n'est pas un lot en attente de remise. La remise est engagée, et son issue n'est pas encore connue : un consentement bancaire qui n'a pas encore été donné, un fichier SEPA en cours de génération, ou un canal qui n'a pas répondu à temps. finished_at reste null tant que le canal n'a pas donné de réponse définitive.
Tant que le lot reste dans cette situation, ses instructions ne peuvent pas être remises une seconde fois. Interrogez le lot jusqu'à ce qu'il quitte approved, ou attendez l'événement payment_batch.updated qui annonce chaque changement d'état : il passe à submitted, puis à completed, partially_completed ou rejected si la réponse du canal porte déjà l'issue de chaque instruction, ou à failed.
Où en est la remise : submission_status
state reste approved tant que la remise engagée n'a pas d'issue. submission_status dit laquelle de ces situations le lot traverse :
submission_status | Ce qu'il signifie |
|---|---|
none | Aucune remise n'a été engagée |
awaiting_consent | La demande de paiement a été créée ; le titulaire du compte ne l'a pas encore autorisée sur la page de sa banque |
in_progress | Le canal produit encore la remise, par exemple un fichier SEPA en cours de génération |
unknown | Aucune réponse exploitable du canal n'est arrivée |
accepted | Le canal a pris le lot |
refused | La remise a été refusée, par le prestataire ou par Scribee avant tout envoi : le lot est failed, et submission_refused_by dit par qui |
Un lot sepa_file dont la remise est engagée lit in_progress tant que son fichier est en cours de génération, et unknown sinon, jusqu'à ce qu'une issue soit enregistrée.
Ni awaiting_consent, ni in_progress, ni unknown ne signifie que le paiement est annulé ou refusé. Le lot reste approved, un paiement peut encore avoir lieu, et Scribee refuse toute nouvelle remise de ce lot tant que c'est le cas. Une page de consentement fermée, un retour sans succès ou une attente prolongée ne prouvent ni une annulation ni un refus : seule une réponse du canal fait sortir le lot de approved.
Une vérification à faire : verification_required
verification_required vaut true quand un lot hosted_consent a sa remise awaiting_consent ou unknown et qu'elle a été engagée il y a 24 heures ou plus (submitted_at). Il vaut toujours false sur un lot sepa_file. Il repasse à false dès que chacune des instructions du lot est settled et porte un bank_operation_id : la banque montre déjà l'argent sorti du compte, il n'y a plus rien à vérifier. C'est une simple lecture : l'état du lot ne change pas, rien n'est libéré, et le prestataire reste interrogé pour son statut définitif. C'est une indication, pas une conclusion : le paiement doit être vérifié auprès du prestataire, et le lot n'a été ni annulé ni refusé. Scribee n'en tire aucun changement d'état, ne libère rien, et continue de refuser une nouvelle remise.
verification_required est calculé à chaque lecture. Il peut passer à true sans changement d'état, donc sans événement payment_batch.updated : lisez le lot pour le connaître.
Quand une remise échoue
error_code vaut operation_failed dès que la dernière tentative de remise porte un diagnostic, et null sinon. error_message est alors une phrase rédigée par Scribee, jamais le texte brut renvoyé par le canal.
Qui a refusé la remise : submission_refused_by
Un lot ne passe à failed que lorsque sa remise engagée a été refusée de façon certaine. submission_refused_by dit par qui :
submission_refused_by | Ce qu'il signifie |
|---|---|
provider | Le prestataire de paiement a renvoyé un refus pour le lot |
local | Scribee a refusé le lot avant tout envoi : le prestataire ne l'a jamais reçu, et aucun résultat bancaire n'est enregistré. Par exemple un lot incomplet, ou un fichier SEPA qui échoue à sa validation |
null | Le lot n'a pas été refusé, ou il l'a été avant que cette information soit enregistrée : l'origine du refus n'est pas connue |
error_message donne la raison du refus. Le refus du lot, à lui seul, n'enregistre aucun résultat bancaire pour ses instructions : il ne confirme ni n'exclut un rejet ou une exécution à la banque. Seule une instruction que la réponse du prestataire signale elle-même comme refusée passe à rejected (Le statut d'une instruction). Un lot failed n'est jamais remis une seconde fois.
error_code peut être renseigné sur un lot approved. Il décrit la dernière tentative - un canal qui n'a pas répondu, par exemple - et non l'issue du lot. Seul l'état failed dit que la remise a échoué. rejected dit autre chose : la remise a abouti, et la banque a refusé chaque instruction.
retryable dit si une nouvelle tentative peut plausiblement aboutir autrement. Il vaut false sur un lot qui n'a jamais été remis.
Être notifié d'un changement d'état
Plutôt que d'interroger les lots en boucle, abonnez un endpoint webhook à payment_batch.updated (Webhooks). L'événement est émis à chaque changement d'état d'un lot, et à ce seul moment ; il porte le nouvel état dans state et l'état quitté dans previous_state. Les dix transitions qui l'émettent, et les huit clés de son corps, sont décrites sur la page Webhooks.
Le changement du status publié d'une instruction est annoncé à part, par payment_instruction.updated, qui porte le statut quitté dans previous_status (Webhooks).
Les instructions d'un lot
curl https://app.scribee.tech/api/v1/payment_batches/7301/instructions \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Les instructions sortent dans l'ordre croissant de leur identifiant, paginées comme les lots. Une instruction se lit aussi seule, par GET /api/v1/payment_instructions/{id} :
{
"data": {
"id": 61004,
"payment_batch_id": 7301,
"company_id": 34,
"invoice_document_id": 88120,
"beneficiary_name": "Papeterie Martin SARL",
"beneficiary_iban_masked": "FR*********************0189",
"beneficiary_iban_last4": "0189",
"amount": 830.0,
"currency_code": "EUR",
"execution_date": "2026-08-29",
"reference": "FA-2026-0310",
"end_to_end_id": "SCB-6100-78010",
"status": "submitted",
"created_at": "2026-08-26T16:41:15+02:00",
"updated_at": "2026-08-26T16:41:15+02:00"
}
}
invoice_document_id désigne la facture que l'instruction règle, quand elle en règle une ; il vaut null sinon. end_to_end_id est l'identifiant de bout en bout du virement, unique, 35 caractères au plus.
L'IBAN du bénéficiaire n'est jamais publié en entier. beneficiary_iban_masked en garde les deux premiers caractères et les quatre derniers, et remplace tous les autres par * ; beneficiary_iban_last4 porte ces quatre derniers caractères. Une valeur de moins de huit caractères est entièrement masquée, et son beneficiary_iban_last4 vaut null.
Le statut d'une instruction
status | Ce qu'il signifie |
|---|---|
draft | Le lot de l'instruction n'a pas engagé de remise |
submitted | Le lot de l'instruction a engagé une remise, et la banque n'a pas donné de réponse sur cette instruction |
submission_failed | La remise du lot a été refusée, et aucun résultat bancaire n'est enregistré pour cette instruction. Le lot est failed et n'est pas remis de nouveau |
pending | La banque a accepté l'instruction et ne l'a pas encore exécutée. Certaines banques ne confirment jamais au-delà : ne la traitez pas comme payée |
settled | La banque a signalé l'exécution de l'instruction, ou une personne a confirmé l'opération bancaire qui l'a réglée |
rejected | La banque a refusé l'instruction, ou une personne a déclaré qu'elle n'a pas été exécutée. Ce statut est définitif |
draft, submitted et submission_failed ne disent rien de l'issue de l'instruction à la banque ; pending, settled et rejected en disent quelque chose. Approuver un lot ne change pas ses instructions : elles restent draft jusqu'à ce que le lot engage sa remise. Une instruction passe à submitted au moment où son lot engage sa remise. Elle y reste tant que l'issue de la remise n'est pas connue - consentement en attente, fichier SEPA en cours de génération, réponse du canal perdue -, comme sur un lot sepa_file dont aucun règlement n'a été confirmé. Elle passe à submission_failed quand le lot passe à failed, que le refus vienne du prestataire ou de Scribee avant tout envoi ; une instruction qui porte déjà un statut de la banque garde le sien. Une exception : quand la réponse du prestataire qui refuse la remise signale elle-même une instruction du lot comme refusée, cette instruction passe à rejected, et non à submission_failed. Les autres instructions du lot passent à submission_failed ; un lot failed peut donc porter les deux statuts, que le filtre status sépare. L'API ne publie pas le motif de ce refus. Sur un lot partially_completed, chaque instruction est settled ou rejected.
submission_failed n'est pas un résultat bancaire enregistré pour cette instruction : il ne confirme ni n'exclut un rejet ou une exécution à la banque - voyez la raison du refus du lot (error_message). Pour savoir qui a refusé la remise, lisez submission_refused_by sur le lot (Qui a refusé la remise).
settled ne se quitte que dans un cas : l'annulation d'un règlement confirmé, sur une instruction dont la banque n'a pas signalé l'exécution. L'instruction revient alors à pending.
Ni l'état d'un lot ni le statut d'une instruction n'enregistrent le paiement d'une facture. Sur cette surface, seule la confirmation d'un règlement l'enregistre.
Deux filtres, facultatifs et cumulables, sur la liste des instructions d'un lot :
| Filtre | Valeurs | Ce qu'il retient |
|---|---|---|
status | draft, submitted, submission_failed, pending, settled, rejected | Les instructions qui publient ce statut |
invoice_document_id | un entier | Les instructions qui règlent cette facture |
Comme sur les lots, un filtre que nous ne savons pas appliquer rend une collection vide.
Les suggestions de règlement d'un lot
curl https://app.scribee.tech/api/v1/payment_batches/7301/settlement \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Cette lecture rend une ligne par instruction du lot, dans l'ordre croissant de payment_instruction_id. Elle n'est pas paginée et ne porte pas de clé meta : la collection est bornée par les instructions du lot.
{
"data": [
{
"payment_instruction_id": 61004,
"state": "matched",
"requires_review": false,
"bank_operation_id": 30401,
"invoice_payment_id": 51120,
"execution_to_confirm_at": null,
"not_executed_declaration": null,
"provider_evidence_conflict_at": null,
"late_provider_events": [],
"candidate_bank_operation_ids": [],
"matched_on": ["amount"],
"suggestions": []
},
{
"payment_instruction_id": 61005,
"state": "ambiguous",
"requires_review": true,
"bank_operation_id": null,
"invoice_payment_id": null,
"execution_to_confirm_at": null,
"not_executed_declaration": null,
"provider_evidence_conflict_at": null,
"late_provider_events": [],
"candidate_bank_operation_ids": [30402],
"matched_on": ["amount"],
"suggestions": [
{
"id": 91204,
"payment_instruction_id": 61005,
"bank_operation_id": 30402,
"state": "proposed",
"amount_match": "exact",
"day_offset": 2,
"window_start": "2026-08-24",
"window_end": "2026-09-08",
"explanation": "Outgoing operation of the same amount and currency booked 2 days after the planned execution date (2026-08-29), within the review window 2026-08-24 to 2026-09-08."
}
]
},
{
"payment_instruction_id": 61006,
"state": "unmatched",
"requires_review": false,
"bank_operation_id": null,
"invoice_payment_id": null,
"execution_to_confirm_at": null,
"not_executed_declaration": null,
"provider_evidence_conflict_at": null,
"late_provider_events": [],
"candidate_bank_operation_ids": [],
"matched_on": [],
"suggestions": []
}
]
}
Une suggestion est une opération bancaire qui ressemble au débit d'une instruction : une opération sortante du compte débité par le lot, dans la même devise, d'un montant exactement égal à celui de l'instruction, et datée dans la fenêtre d'examen. Une opération déjà rapprochée de factures au moment du calcul n'est pas suggérée.
Une suggestion ne prouve ni le règlement de l'instruction, ni le paiement de la facture. Elle est proposée à l'examen d'une personne, et rien de plus : elle ne change pas le status de l'instruction ni l'état du lot, et n'enregistre aucun paiement de facture. Seule une confirmation le fait (Confirmer le règlement d'une instruction).
Lire une ligne
| Clé | Ce qu'elle porte |
|---|---|
state | unmatched quand aucune opération n'est suggérée ; ambiguous quand une ou plusieurs le sont et qu'une personne doit les examiner ; matched quand l'opération qui a réglé l'instruction a été confirmée |
requires_review | true quand state vaut ambiguous, false sinon |
bank_operation_id | L'opération confirmée ; null tant que state ne vaut pas matched |
invoice_payment_id | Le paiement de facture que la confirmation a enregistré ou repris ; null tant que state ne vaut pas matched, et sur une instruction qui ne règle aucune facture |
execution_to_confirm_at | Une date et une heure ISO 8601 quand le règlement confirmé de l'instruction a été annulé sans que la banque ait signalé son exécution : l'instruction est revenue à pending, et son exécution reste à confirmer. null sur toute autre instruction, et de nouveau dès que la banque signale l'exécution ou le rejet de l'instruction, qu'une opération bancaire est confirmée pour elle, ou qu'elle est déclarée non exécutée |
not_executed_declaration | La déclaration de non-exécution de l'instruction : reason, note et declared_at, une date et une heure ISO 8601. null sur toute instruction qui n'a pas été déclarée non exécutée, y compris une instruction refusée par la banque |
provider_evidence_conflict_at | Une date et une heure ISO 8601 quand un compte rendu de la banque, reçu alors que l'instruction était settled, l'a contredite : l'instant de réception du premier. null sinon. Il ne change pas le state de la ligne |
late_provider_events | Les comptes rendus de la banque reçus après coup, conservés sans être appliqués, du plus ancien au plus récent reçu : scheme_status_code, occurred_at et received_at. [] sinon |
candidate_bank_operation_ids | Les identifiants des opérations suggérées, dans l'ordre croissant |
matched_on | ["amount"] quand au moins une opération est suggérée ou confirmée, [] sinon |
suggestions | Le détail de chaque opération suggérée, dans le même ordre ; vide sur une ligne matched |
Une seule opération suggérée donne aussi ambiguous : l'API ne choisit jamais un candidat à votre place.
Chaque élément de suggestions porte :
| Clé | Ce qu'elle porte |
|---|---|
id | L'identifiant de la suggestion, que l'écarter ou la confirmer désigne |
payment_instruction_id | L'instruction concernée |
bank_operation_id | L'opération suggérée, lisible sur Opérations bancaires |
state | Toujours proposed : la suggestion attend un examen |
amount_match | Toujours exact : l'opération porte exactement le montant de l'instruction, dans la même devise |
day_offset | Le nombre de jours calendaires entre la date de l'opération et la date de référence de la fenêtre, négatif quand l'opération est antérieure |
window_start, window_end | Le premier et le dernier jour de la fenêtre d'examen parcourue |
explanation | Une phrase en anglais qui dit pourquoi l'opération a été suggérée |
La fenêtre d'examen
La fenêtre va de 5 jours avant à 10 jours après une date de référence, en jours calendaires, bornes incluses. La date de référence est l'execution_date de l'instruction, à défaut celle du lot, à défaut le jour de submitted_at. Une opération datée hors de la fenêtre n'est jamais suggérée ; la recherche manuelle la trouve.
La fenêtre filtre les candidats ; elle ne prouve pas le règlement.
Quand les suggestions sont calculées
Scribee calcule les suggestions en arrière-plan, et non au moment de votre lecture : quand la banque communique un statut pour les instructions du lot, quand de nouvelles opérations bancaires arrivent pour l'entreprise, par synchronisation bancaire ou par un relevé importé, et après l'annulation d'un règlement. Une suggestion n'est calculée que pour une instruction qui n'est pas rejected et n'est pas déjà rapprochée, dans un lot submitted, completed ou partially_completed, ou approved avec un submitted_at renseigné.
Chaque calcul retire les suggestions dont l'opération n'est plus candidate - une instruction devenue rejected, une opération rapprochée de factures entre-temps - et elles disparaissent de la ligne. Seules les suggestions en attente d'examen sont publiées.
Comme pour la lecture d'un lot, un lot que vos habilitations ne couvrent pas répond 404, même si le rapprochement bancaire est désactivé dans son workspace.
Un compte rendu de la banque reçu après coup
Une fois settled, une instruction ne change plus de statut sur un compte rendu de la banque. Quand la banque en communique un malgré tout sur cette instruction - son règlement a pu être confirmé avant que la banque ait répondu -, Scribee le conserve sans l'appliquer :
- le
statusde l'instruction, lestatede sa ligne de règlement, sonbank_operation_idet soninvoice_payment_idne changent pas ; - aucun paiement de facture n'est enregistré ni retiré, et aucun montant de facture n'est réservé ni libéré ;
- la conservation du compte rendu ne change ni l'état ni la
versiondu lot.
La ligne de règlement publie ces comptes rendus dans late_provider_events, du plus ancien au plus récent reçu. Un compte rendu qui répète le statut et le code que l'instruction porte déjà n'y figure pas, un ACSC non plus : il confirme l'exécution de l'instruction, et il est conservé comme tel (Annuler un règlement confirmé). Un même code n'y figure qu'une fois, même quand la banque le répète à chaque lecture.
| Clé | Ce qu'elle porte |
|---|---|
scheme_status_code | Le code ISO 20022 que la banque a communiqué |
occurred_at | L'instant où ce statut a été constaté, une date et une heure ISO 8601 ; null quand il n'est pas connu |
received_at | L'instant où Scribee a reçu le compte rendu, une date et une heure ISO 8601 |
Un rejet reçu après le règlement contredit l'instruction. Quand la banque communique un RJCT sur une instruction settled, la ligne de règlement porte provider_evidence_conflict_at, l'instant de réception de ce premier compte rendu contradictoire. Le champ n'est écrit qu'une fois et n'est jamais remis à null : un compte rendu contradictoire suivant s'ajoute à late_provider_events sans le changer. Tout autre code est conservé sans renseigner ce champ.
{
"payment_instruction_id": 61004,
"state": "matched",
"requires_review": false,
"bank_operation_id": 30401,
"invoice_payment_id": 51120,
"execution_to_confirm_at": null,
"not_executed_declaration": null,
"provider_evidence_conflict_at": "2026-09-29T10:00:00+02:00",
"late_provider_events": [
{
"scheme_status_code": "RJCT",
"occurred_at": "2026-09-29T10:00:00+02:00",
"received_at": "2026-09-29T10:00:00+02:00"
}
],
"candidate_bank_operation_ids": [],
"matched_on": ["amount"],
"suggestions": []
}
provider_evidence_conflict_at ne tranche rien. L'instruction reste settled, et le paiement de facture que la confirmation a enregistré reste en place : la contradiction est à examiner par une personne. Si le règlement confirmé se révèle erroné, annulez-le.
Aucun webhook ne signale un compte rendu reçu après coup. Sa conservation ne change pas l'état du lot, et payment_batch.updated n'est émis que sur un changement d'état ; aucun autre événement webhook ne le signale. Pour le détecter, lisez la ligne de règlement : GET /api/v1/payment_batches/{id}/settlement.
Agir sur le règlement d'une instruction
Cinq opérations transforment ces suggestions en décisions : écarter une suggestion, chercher une opération hors de la fenêtre, confirmer l'opération qui a réglé une instruction, annuler cette confirmation, et déclarer non exécutée une instruction dont l'exécution est à confirmer.
Aucune d'elles n'exécute, n'annule ni ne transmet un virement à la banque. Elles enregistrent dans Scribee ce que vous constatez sur le compte. Confirmer enregistre le paiement de la facture de l'instruction ; annuler retire ce que la confirmation a enregistré, et rien d'autre ; déclarer une non-exécution libère le montant réservé de la facture.
| Opération | Scope | Idempotency-Key |
|---|---|---|
GET /api/v1/payment_batches/{id}/settlement/candidates | read | sans objet |
POST /api/v1/payment_batches/{id}/settlement/suggestions/{suggestion_id}/dismiss | write | acceptée, facultative |
POST /api/v1/payment_batches/{id}/settlement/suggestions/{suggestion_id}/confirm | write | exigée |
POST /api/v1/payment_batches/{id}/settlement/confirm | write | exigée |
POST /api/v1/payment_batches/{id}/settlement/instructions/{payment_instruction_id}/undo | write | exigée |
POST /api/v1/payment_batches/{id}/settlement/instructions/{payment_instruction_id}/not_executed | write | exigée |
La clé est exigée sur la confirmation et l'annulation parce qu'elles s'annulent l'une l'autre : rejouer une confirmation après une annulation confirmerait de nouveau. Elle l'est aussi sur la déclaration de non-exécution, qui libère le montant réservé de la facture. Avec la même clé, un rejeu renvoie la réponse enregistrée.
Écarter une suggestion
curl -X POST https://app.scribee.tech/api/v1/payment_batches/7301/settlement/suggestions/91204/dismiss \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Écarter dit « cette opération n'a pas réglé cette instruction ». La réponse 200 porte la suggestion, dont state vaut désormais dismissed.
Rien d'autre ne change : ni le status de l'instruction, ni l'état du lot, ni la facture, ni la comptabilité. La suggestion disparaît de la ligne, et cette paire n'est plus jamais suggérée. Écarter une suggestion déjà écartée répond le même 200. Une suggestion retirée entre-temps par un calcul ou par une confirmation est refusée par un 422 operation_failed : elle n'est plus devant personne.
Chercher une opération hors de la fenêtre
curl "https://app.scribee.tech/api/v1/payment_batches/7301/settlement/candidates?payment_instruction_id=61005&from=2026-09-01&to=2026-10-31" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
{
"data": [
{
"bank_operation_id": 30405,
"operation_date": "2026-10-13",
"amount_match": "exact",
"day_offset": 45
}
]
}
Un débit arrivé tard, ou un relevé importé des mois après, tombe hors de la fenêtre d'examen. Cette recherche parcourt les dates que vous choisissez, avec les mêmes contrôles que les suggestions : le compte débité par le lot, une opération sortante, la même devise, le montant exact, et une opération qu'aucune autre instruction ni aucune facture n'a prise.
payment_instruction_id,fromettosont exigés ; les dates s'écriventAAAA-MM-JJ.ton'est pas antérieure àfrom, et la plage couvre au plus 366 jours, bornes incluses.- L'instruction appartient au lot, et une suggestion pourrait lui être calculée : elle n'est pas
rejected, n'est pas déjà rapprochée, et son lot a atteint la banque.
Les résultats sortent par date d'opération croissante, sans pagination. day_offset compte les jours depuis la date de référence de l'instruction. Rien n'est enregistré : un résultat n'est pas une suggestion, n'apparaît pas dans la vue de règlement et ne sera pas suggéré plus tard. Pour le retenir, confirmez-le directement.
Un paramètre refusé répond un 422 validation_failed, avec details indexé par le nom du paramètre.
Confirmer le règlement d'une instruction
Confirmer enregistre le paiement de la facture de l'instruction et la passe à settled. Rien ne part vers la banque, et l'annulation défait ce que la confirmation a enregistré.
Pour une suggestion, désignez-la par son id :
curl -X POST https://app.scribee.tech/api/v1/payment_batches/7301/settlement/suggestions/91204/confirm \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Idempotency-Key: 3c9e7a12-5f0b-4d6e-8a41-72b9c0d5e813"
Pour un résultat de la recherche manuelle, nommez la paire dans le corps :
curl -X POST https://app.scribee.tech/api/v1/payment_batches/7301/settlement/confirm \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Idempotency-Key: 9a41d2c7-0e3b-4f58-b6a2-5c18e7f094d3" \
-H "Content-Type: application/json" \
-d '{ "payment_instruction_id": 61005, "bank_operation_id": 30405, "expected_version": 6 }'
Les deux formes font la même chose :
- La paire est contrôlée de nouveau au moment de la confirmation, avec les contrôles des suggestions, sur la date de l'opération elle-même : la fenêtre limite les suggestions, jamais une confirmation. L'opération ne doit régler aucune autre instruction, ni avoir été rapprochée d'une autre facture.
- La facture est payée par le rapprochement bancaire. Si l'opération était déjà rapprochée de cette même facture, ce rapprochement et son paiement sont repris, jamais dupliqués. Une instruction qui ne règle aucune facture est rapprochée seule, sans paiement : son
invoice_payment_idrestenull. - Tant que ce lien existe, les affectations de l'opération ne changent que par l'annulation de ce règlement. L'opération ne peut être soldée contre aucune autre facture que celle de l'instruction - contre aucune, pour une instruction qui ne règle aucune facture -, et ses affectations ne peuvent être ni annulées ni redimensionnées :
POSTetDELETEsur/api/v1/bank_operations/{id}/reconciliation, etPATCH /api/v1/bank_allocations/{id}, répondent par un422operation_failed(Affectations et rapprochement). - L'instruction devient
settled. Quand le lot estsubmittedet que chacune de ses instructions a un statut définitif, il passe àcompletedoupartially_completed, etpayment_batch.updatedest émis (Webhooks). - La suggestion confirmée, et toute autre suggestion de l'instruction ou de l'opération, disparaissent de la vue de règlement.
La réponse est un 200 portant la ligne de règlement de l'instruction, matched. Confirmer la paire déjà confirmée répond le même 200, sans rien écrire, quelle que soit la version envoyée.
Le corps peut porter expected_version, la version du lot telle que vous l'avez lue ; il est facultatif sur les deux formes. Un lot qui a changé depuis est refusé par un 409 stale_version, et rien n'est confirmé.
Annuler un règlement confirmé
curl -X POST https://app.scribee.tech/api/v1/payment_batches/7301/settlement/instructions/61005/undo \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Idempotency-Key: d6b0f3a8-2c71-4e95-9f14-8e3a5b27c160"
Annuler ne rembourse rien et n'annule aucun virement à la banque. L'annulation retire le lien entre l'instruction et son opération, et seulement ce que la confirmation en avait tiré :
- Le paiement de facture que la confirmation a enregistré est retiré, et lui seul : celui que l'instruction désigne par son
invoice_payment_id. Une écriture comptable déjà exportée n'est jamais réécrite : une écriture de correction est passée. Un rapprochement de l'opération avec la facture qui existait avant la confirmation, et son paiement, restent en place, comme tout paiement que la confirmation n'a pas enregistré : l'annulation ne retire alors que le lien. - Les comptes rendus de la banque sont conservés.
- Si la banque a signalé l'exécution de l'instruction, elle reste
settled, et le lot garde son état. C'est vrai aussi quand ce signalement est arrivé après la confirmation : il ne change pas lestatusde l'instruction, déjàsettled, mais il est conservé. - Sinon, l'instruction revient à
pending- exécution à confirmer. Elle garde le montant de sa facture réservé, et elle n'est jamais remise une seconde fois à la banque. Un lotcompletedoupartially_completedrevient àsubmitted, etpayment_batch.updatedest émis. La ligne de règlement porte alorsexecution_to_confirm_at, l'instant de l'annulation.
execution_to_confirm_at ne dit pas que le paiement a été annulé. L'absence d'opération bancaire ne prouve pas que le virement n'a pas été exécuté : son exécution n'est simplement plus démontrée. Le champ ne change pas le state de la ligne. Il revient à null quand la banque signale l'exécution de l'instruction, qui devient settled, quand elle la rejette, qui devient rejected, ou quand une opération bancaire est confirmée pour elle. Un nouveau statut pending communiqué par la banque le laisse en place. Sur un lot sepa_file, vous pouvez aussi déclarer l'instruction non exécutée.
La réponse est un 200 portant la ligne de règlement de l'instruction. Scribee recalcule ensuite les suggestions du lot en arrière-plan : l'opération peut être suggérée de nouveau, sous un nouvel id, sauf si vous l'aviez écartée. Une nouvelle confirmation repasse l'instruction à settled.
Annuler une instruction qui n'est pas rapprochée répond le même 200, sans rien écrire, quelle que soit la version envoyée. Le corps accepte le même expected_version facultatif que la confirmation.
Déclarer une instruction non exécutée
curl -X POST https://app.scribee.tech/api/v1/payment_batches/6100/settlement/instructions/78012/not_executed \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Idempotency-Key: 5e2c8b71-a0d4-4f39-8c6e-1b7d93f24a05" \
-H "Content-Type: application/json" \
-d '{ "reason": "file_not_uploaded", "note": "The SEPA file was never uploaded to the bank portal.", "expected_version": 9 }'
Une instruction dont l'exécution est à confirmer - son execution_to_confirm_at est renseigné - garde le montant de sa facture réservé tant que rien ne tranche. Ce qui peut trancher dépend du canal du lot :
channel du lot | Ce qui résout une exécution à confirmer |
|---|---|
hosted_consent | Ce que la banque signale - l'exécution ou le rejet de l'instruction -, ou la confirmation d'une opération bancaire. Une déclaration de non-exécution est refusée |
sepa_file | La confirmation d'une opération bancaire, ou votre déclaration de non-exécution : aucune banque ne répond à Scribee sur un fichier que vous avez transmis vous-même |
Une opération bancaire absente ne prouve pas que le paiement n'a pas été exécuté. Ne trouver aucun débit sur le compte ne suffit pas : déclarez une non-exécution quand vous la constatez, et dites laquelle.
| Champ | Ce qu'il porte |
|---|---|
reason | Exigé. Pourquoi le paiement n'a pas été exécuté : file_not_uploaded, le fichier n'a jamais été déposé à la banque ; rejected_by_bank_portal, le portail de la banque l'a refusé ; cancelled_at_bank, il a été annulé à la banque |
note | Exigé. Votre explication, conservée avec la déclaration : 2000 caractères au plus, une fois retirés les espaces qui l'entourent |
expected_version | Facultatif. La version du lot telle que vous l'avez lue ; un lot qui a changé depuis est refusé par un 409 stale_version, et rien n'est déclaré |
L'instruction doit appartenir au lot, et son exécution doit être à confirmer. Une instruction dont le règlement est confirmé ne se déclare pas : annulez d'abord ce règlement.
La déclaration :
- passe l'instruction à
rejected, définitivement, et remet sonexecution_to_confirm_atànull. La ligne de règlement portenot_executed_declaration, qui distingue votre déclaration d'un refus signalé par la banque ; - libère le montant réservé de la facture : un nouveau lot, créé dans Scribee, peut la régler ;
- ne remet rien à la banque : l'instruction déclarée n'est jamais remise une seconde fois, et aucun nouveau lot n'est créé à votre place ;
- conserve les comptes rendus de la banque ;
- est enregistrée au nom de votre application, avec sa date ;
- change la
versiondu lot. Quand le lot estsubmittedet que chacune de ses instructions a désormais un statut définitif, il passe àrejectedoupartially_completed, etpayment_batch.updatedest émis (Webhooks).
La réponse est un 200 portant la ligne de règlement de l'instruction :
{
"data": {
"payment_instruction_id": 78012,
"state": "unmatched",
"requires_review": false,
"bank_operation_id": null,
"invoice_payment_id": null,
"execution_to_confirm_at": null,
"not_executed_declaration": {
"reason": "file_not_uploaded",
"note": "The SEPA file was never uploaded to the bank portal.",
"declared_at": "2026-09-29T10:15:00+02:00"
},
"provider_evidence_conflict_at": null,
"late_provider_events": [],
"candidate_bank_operation_ids": [],
"matched_on": [],
"suggestions": []
}
}
Renvoyer la même déclaration - même reason, même note - sur une instruction qui la porte déjà répond le même 200, sans rien écrire, quelle que soit la version envoyée. Une déclaration différente est refusée : l'instruction n'est plus à confirmer.
Les refus
| Statut | code | Quand |
|---|---|---|
422 | validation_failed | L'Idempotency-Key manque sur une confirmation, une annulation ou une déclaration ; expected_version ne se lit pas comme un entier ; sur POST .../settlement/confirm, l'instruction n'appartient pas au lot ou l'opération n'appartient pas à l'entreprise du lot ; sur une déclaration, reason ou note est présent sans être une chaîne JSON, reason n'est pas l'une des trois valeurs, ou note est vide ou dépasse 2000 caractères. details nomme chaque champ refusé |
422 | operation_failed | La paire est refusée, et message dit pourquoi : la suggestion n'est plus proposée, l'instruction est déjà rapprochée d'une autre opération ou ne peut pas être réglée, l'opération règle déjà une autre instruction, est rapprochée d'une autre facture ou ne passe pas les contrôles, ou le rapprochement bancaire refuse le paiement de la facture. Sur une annulation : le paiement enregistré ne peut pas être retiré. Sur une déclaration : le lot n'est pas un lot sepa_file, ou l'exécution de l'instruction n'est pas à confirmer. Sur toutes : le lot est en cours de mise à jour, réessayez dans un instant |
409 | stale_version | expected_version ne correspond plus à la version du lot. Rien n'a été confirmé, annulé ni déclaré ; details.current_version porte la version actuelle et details.payment_batch le lot |
409 | idempotency_key_reuse | La même Idempotency-Key accompagne une requête différente |
409 | idempotency_request_in_progress | Un appel portant la même Idempotency-Key est encore en cours |
404 | not_found | Le lot n'est pas atteignable par vos habilitations, ou la suggestion ou l'instruction du chemin n'appartient pas à ce lot |
Embarquer les ressources liées
La liste et la lecture des lots acceptent include, avec une ou deux valeurs séparées par une virgule :
include | Clé ajoutée | Contenu |
|---|---|---|
payment_instructions | payment_instructions | Toutes les instructions du lot, non paginées, dans l'ordre croissant de leur identifiant |
bank_account | bank_account | Le compte débité, avec la charge utile complète de Comptes bancaires |
Sans include, ces clés sont absentes - et non pas présentes à null. Toute autre valeur est ignorée. Les instructions n'acceptent aucun include.
Les montants
total_amount et amount sont des nombres JSON arrondis à deux décimales, et non des chaînes : 1250.50 s'écrit 1250.5. total_amount est la somme des montants des instructions du lot.
Préparer, approuver et remettre un lot
Sept opérations mènent un lot de sa création à sa remise. Elles appliquent les règles du centre de paiement de Scribee : un lot préparé par l'API porte les mêmes instructions, les mêmes identifiants et les mêmes refus qu'un lot préparé à l'écran.
Le parcours complet
POST /api/v1/workspaces/{workspace_id}/companies/{company_id}/payment_batchescrée le lot,draft.PATCH /api/v1/payment_batches/{id}le corrige, tant qu'il estdraft.POST /api/v1/payment_batches/{id}/submit_for_approvalle passe àpending_approval.POST /api/v1/payment_batches/{id}/approvele passe àapproved.POST /api/v1/payment_batches/{id}/refusele renvoie àdraft, où il se corrige avant d'être soumis de nouveau.POST /api/v1/payment_batches/{id}/submitremet un lothosted_consentapprouvé à son canal. Un lotsepa_fileest remis parPOST /api/v1/payment_batches/{id}/sepa_export(Générer et télécharger le fichier SEPA).POST /api/v1/payment_batches/{id}/consent_sessionpublie, pour un lothosted_consent, la page où le titulaire du compte donne son consentement (Reprendre le consentement).GET /api/v1/payment_batches/{id}suit le lot jusqu'à ce qu'il quitteapproved, ou l'événementpayment_batch.updatedvous l'annonce (Être notifié d'un changement d'état).
Aucune de ces étapes ne prouve qu'un virement a été exécuté, pas même la remise : seuls l'état du lot et le statut de ses instructions en disent quelque chose (Les états d'un lot).
Version et idempotence
| Opération | Idempotency-Key | expected_version | Succès |
|---|---|---|---|
POST /api/v1/workspaces/{workspace_id}/companies/{company_id}/payment_batches | exigée | sans objet | 201 |
PATCH /api/v1/payment_batches/{id} | acceptée, facultative | facultatif | 200 |
POST /api/v1/payment_batches/{id}/submit_for_approval | exigée | facultatif | 200 |
POST /api/v1/payment_batches/{id}/approve | exigée | exigé | 200 |
POST /api/v1/payment_batches/{id}/refuse | exigée | facultatif | 200 |
POST /api/v1/payment_batches/{id}/submit | exigée | exigé | 202 |
POST /api/v1/payment_batches/{id}/consent_session | ignorée | sans objet | 200 |
Les sept exigent le scope write, et aucun autre : l'approbation n'a pas de scope à part. Un token portant write, avec une habilitation sur le workspace du lot, peut approuver le lot qu'il a préparé. Scribee ne vérifie pas que l'approbation vient d'un autre client OAuth que la préparation ; si votre organisation sépare ces deux rôles, cette séparation est de votre ressort.
expected_version est la version du lot telle que vous l'avez lue, envoyée dans le corps de la requête. Sur les quatre transitions, le corps ne porte rien d'autre. Un lot qui a changé depuis votre lecture est refusé par un 409 stale_version, et rien n'est écrit ni envoyé ; details.current_version porte la version actuelle et details.payment_batch le lot tel que GET /api/v1/payment_batches/{id} le publie. Relisez-le, vérifiez que l'action a toujours lieu d'être, puis renvoyez l'appel avec details.current_version. Un expected_version exigé et absent, ou qui ne se lit pas comme un entier, est refusé par un 422 validation_failed, avec details.expected_version.
Avec la même Idempotency-Key, un rejeu renvoie la réponse enregistrée : un lot n'est pas créé deux fois, et une remise n'atteint jamais deux fois le canal. Sans elle, deux créations identiques créent deux lots. Seul un succès est enregistré : un refus ne consomme pas la clé, et l'appel corrigé peut être renvoyé avec la même clé.
Créer un brouillon
curl -X POST https://app.scribee.tech/api/v1/workspaces/YOUR_WORKSPACE_ID/companies/YOUR_COMPANY_ID/payment_batches \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Idempotency-Key: 2b7e40a1-9c31-4d55-8f0b-6a1c2e93d770" \
-H "Content-Type: application/json" \
-d '{
"bank_account_id": 812,
"name": "Fournisseurs 2026-08",
"channel": "hosted_consent",
"execution_date": "2026-08-29",
"instructions": [
{
"invoice_document_id": 88120,
"amount": 830.0,
"beneficiary_name": "Papeterie Martin SARL",
"beneficiary_iban": "FR7630006000011234567890189",
"reference": "FA-2026-0310"
}
]
}'
La réponse est un 201 portant le lot, draft, sous la forme de sa lecture (Lire un lot).
bank_account_id,channeletinstructionssont exigés ;nameetexecution_datesont facultatifs.channelvauthosted_consentousepa_file.bank_account_iddésigne un compte bancaire de l'entreprise du chemin (Comptes bancaires). Le lot prend la devise de ce compte, ouEURquand le compte n'en porte pas : le corps ne porte pas de devise de lot.instructionsporte au moins une ligne. Chaque ligne exigeamount,beneficiary_nameetbeneficiary_iban.invoice_document_iddésigne la facture de l'entreprise que la ligne règle, ou vautnullpour un paiement qui ne règle aucune facture Scribee.referenceest la référence que le bénéficiaire voit.- Le
currency_coded'une ligne est facultatif et vaut par défaut la devise du lot ; toute autre valeur est refusée. Une ligne qui règle une facture dans une autre devise est refusée aussi : Scribee ne convertit jamais un montant. - L'
execution_dated'une ligne est facultative et vaut par défaut celle du lot. beneficiary_ibanest l'IBAN complet. Les espaces sont acceptés et retirés ; le format et la clé de contrôle sont vérifiés. Il n'est jamais renvoyé : ni cette réponse ni aucune autre ne publie plus quebeneficiary_iban_maskedetbeneficiary_iban_last4(Les instructions d'un lot).- Scribee attribue à chaque ligne son
end_to_end_id.
Un brouillon ne réserve rien et ne déplace aucun argent. Le montant des factures réglées n'est réservé qu'au moment de la remise.
Un bank_account_id ou un invoice_document_id qui ne désigne pas un enregistrement de cette entreprise est refusé par un 422 invalid_argument, que l'enregistrement appartienne à quelqu'un d'autre ou n'existe pas : ce refus ne révèle rien des enregistrements qui ne sont pas les vôtres.
Modifier un brouillon
curl -X PATCH https://app.scribee.tech/api/v1/payment_batches/7301 \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "execution_date": "2026-09-01", "expected_version": 1 }'
La réponse est un 200 portant le lot modifié.
- Seul un lot
draftse modifie. Tout autre état est refusé par un422batch_not_submittable, quelle que soit la version envoyée. Pour corriger un lotpending_approval, refusez son approbation : il revient àdraft. - Seuls les champs envoyés sont écrits. Un champ absent du corps garde sa valeur ;
"name": nullefface le libellé. instructions, quand il est envoyé, remplace l'ensemble des lignes : une ligne absente de la liste est supprimée. Les nouvelles lignes reçoivent leursend_to_end_id, numérotés de nouveau depuis le début.- Changer
bank_account_idchange la devise du lot. Les lignes conservées doivent être dans cette devise, sinon l'appel est refusé : envoyez alorsinstructionsavec le nouveau compte. - Changer
execution_dateentraîne les lignes qui portaient l'ancienne date du lot ; une ligne qui portait sa propre date la garde.
Une modification ne change pas l'état du lot, et n'émet donc pas payment_batch.updated.
Soumettre à approbation, approuver, refuser
curl -X POST https://app.scribee.tech/api/v1/payment_batches/7301/approve \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Idempotency-Key: 5d1f8c3e-7a24-4b90-9e61-0c3b7f2a8d45" \
-H "Content-Type: application/json" \
-d '{ "expected_version": 3 }'
| Opération | État de départ | État d'arrivée | Sur un lot déjà dans l'état d'arrivée |
|---|---|---|---|
POST /api/v1/payment_batches/{id}/submit_for_approval | draft | pending_approval | Refusé : 422 batch_not_submittable |
POST /api/v1/payment_batches/{id}/approve | pending_approval | approved | 200, rien ne change |
POST /api/v1/payment_batches/{id}/refuse | pending_approval | draft | 200, rien ne change |
La réponse est un 200 portant le lot dans son nouvel état.
- Soumettre à approbation exige au moins une instruction, toutes encore valides. Sinon, l'appel est refusé par un
422validation_failed, etdetails.instructionsnomme lesend_to_end_iddes lignes qui ne le sont plus. - Approuver renseigne
approved_at. Le montant total du lot est alors figé. - Refuser renvoie le lot à
draft, où il se modifie de nouveau. - Depuis tout autre état, la transition est refusée par un
422batch_not_submittable.
Chaque transition émet payment_batch.updated ; un appel qui ne change rien n'émet rien (Webhooks).
Savoir qui a approuvé ou refusé un lot
Chaque approbation et chaque refus enregistre qui l'a décidé : l'utilisateur, pour une décision prise dans le centre de paiement Scribee ; l'application API à laquelle le jeton a été délivré, pour un appel à POST /api/v1/payment_batches/{id}/approve ou POST /api/v1/payment_batches/{id}/refuse. Le lot le publie dans deux champs, présents dans toutes ses réponses :
| Champ | Contenu |
|---|---|
approved_by | L'approbation du lot, ou null tant qu'il n'a pas été approuvé |
refused_by | Le refus d'approbation le plus récent, ou null si l'approbation du lot n'a jamais été refusée. Un lot refusé revient à draft et peut être soumis puis approuvé de nouveau : refused_by peut donc désigner un refus antérieur à approved_by |
Chacun porte :
| Champ | Contenu |
|---|---|
actor_type | user pour une décision prise dans le centre de paiement Scribee, api_client pour une décision prise par cette API |
name | Qui a décidé, tel qu'il se nommait à ce moment : pour user, le prénom et le nom de l'utilisateur, ou, s'il n'a renseigné ni l'un ni l'autre, un libellé fixe qui ne l'identifie pas, dans la langue par défaut de la plateforme (le français : « Utilisateur sans nom ») ; pour api_client, le nom de l'application API. Ce n'est jamais une adresse e-mail |
decided_at | La date et l'heure de la décision. Sur approved_by, c'est la valeur de approved_at |
- Seule une décision qui change l'état du lot est enregistrée. Un appel sur un lot déjà dans l'état d'arrivée répond
200sans rien enregistrer. De deux décisions simultanées, seule celle qui fait passer le lot est enregistrée. - Aucun auteur n'est déduit après coup. Une décision prise avant que Scribee n'enregistre son auteur n'en a pas : le lot publie alors
approved_byànullbien queapproved_atsoit renseigné, et un tel refus n'apparaît pas dansrefused_by. - Celui qui soumet un lot peut aussi l'approuver. Scribee n'exige pas que l'approbation vienne d'un autre utilisateur ou d'une autre application que la soumission.
Remettre un lot hosted_consent
curl -X POST https://app.scribee.tech/api/v1/payment_batches/7301/submit \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Idempotency-Key: 8e2a6f14-3c95-4d07-b1e8-9f4a2c6d0b73" \
-H "Content-Type: application/json" \
-d '{ "expected_version": 4 }'
submit remet à son canal un lot approved dont le channel vaut hosted_consent, et qui ne porte encore aucune tentative de remise. Un lot sepa_file est refusé par un 422 batch_not_submittable : il est remis par POST /api/v1/payment_batches/{id}/sepa_export.
Avant d'appeler le canal, Scribee réserve le montant de chaque facture réglée, comme pour un fichier SEPA. Une réservation refusée répond un 422 validation_failed, avec details indexé payment_instructions.<id> et pour valeur already_reserved, exceeds_remaining_due ou currency_mismatch ; le lot reste approved, sans tentative enregistrée, et rien n'est envoyé.
Scribee peut aussi refuser le lot avant tout envoi : quand le canal ne peut pas l'exprimer en l'état, ou quand la demande au prestataire ne peut pas être construite de notre côté. L'appel répond alors un 422 validation_failed, avec details.instructions ; rien n'est envoyé au prestataire, mais le lot passe à failed avec submission_refused_by à local, comme depuis le centre de paiement, ses instructions passent à submission_failed, et payment_batch.updated est émis. Ce refus ne consomme pas l'Idempotency-Key : un nouvel appel est traité de nouveau, mais un lot failed n'est jamais remis.
La réponse est un 202 dès que l'appel a atteint le canal, quelle qu'ait été sa réponse. Un 202 ne signifie jamais que l'argent a bougé. Lisez le lot qu'elle porte :
- une demande de paiement en attente de consentement laisse le lot
approved, avecsubmission_statusàawaiting_consent: le titulaire du compte doit encore l'autoriser sur la page de sa banque ; - une issue inconnue laisse le lot
approved, avecsubmission_statusàunknown; - un refus du prestataire passe le lot à
failed, avecsubmission_refused_byàprovider,error_codeeterror_message; - un canal qui prend le lot le passe à
submitted, ou plus loin si sa réponse porte déjà l'issue de chaque instruction.
Un lot resté approved se suit comme toute remise engagée (Une remise engagée dont l'issue n'est pas connue). La réponse ne porte jamais l'adresse de la page de consentement : POST /api/v1/payment_batches/{id}/consent_session la publie.
Renvoyer submit sur un lot que le canal a déjà pris répond le même 202, sans rien envoyer. Sur un lot dont une tentative est déjà engagée sans avoir été prise - consentement en attente, issue inconnue -, l'appel est refusé par un 422 batch_not_submittable : Scribee ne remet jamais deux fois les instructions d'un lot. Quand une autre requête est en train de remettre le même lot, l'appel est refusé de la même façon, et son message invite à relire le lot dans quelques instants. Quand aucun canal n'est disponible pour ce lot, l'appel est refusé par un 422 operation_failed. Aucun de ces refus n'a rien envoyé.
Reprendre le consentement d'un lot hosted_consent
curl -X POST https://app.scribee.tech/api/v1/payment_batches/7301/consent_session \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
{
"data": {
"payment_batch_id": 7301,
"state": "pending",
"consent_url": "https://consent.example.com/payments/7Hq2/authorize",
"consent_url_expires_at": null
}
}
Un lot hosted_consent remis attend que le titulaire du compte autorise le paiement sur la page de sa banque. POST /api/v1/payment_batches/{id}/consent_session publie l'adresse de cette page. Le consentement se donne dans un navigateur, par le titulaire du compte : aucun appel de l'API ne le donne à sa place. Transmettez consent_url à cette personne, qui l'ouvre dans son navigateur.
- Il n'y a de consentement qu'après
submit. Un lot qui ne porte encore aucune tentative de remise, ou un lotsepa_file, est refusé par un422batch_not_submittable, sans que le prestataire de paiement soit interrogé. - Rien n'est créé, et rien n'est envoyé une seconde fois. La réponse est un
200, sansidni horodatage : le consentement n'est pas une ressource enregistrée. Chaque appel interroge de nouveau le prestataire sur la demande de paiement quesubmita créée ; un lot dont la remise est déjà résolue est répondu depuis son état, sans l'interroger. - Cette interrogation peut faire évoluer le lot. Un consentement que le prestataire a depuis accepté, laissé expirer ou refusé fait sortir le lot de
approved, comme toute réponse du canal, etpayment_batch.updatedest émis. - Le scope
writeest exigé.
state | Ce qu'il signifie |
|---|---|
pending | Le titulaire du compte n'a pas encore consenti, ou la réponse du prestataire n'est pas connue. Le lot reste approved |
completed | Le prestataire a pris le paiement. Ce n'est pas la preuve que l'argent a bougé : suivez le lot et ses instructions |
expired | Le prestataire indique que le consentement a expiré sans avoir été donné. Le lot est failed |
failed | Le prestataire a refusé le consentement pour une autre raison. Le lot est failed |
consent_url n'est renseignée que lorsque state vaut pending et que le prestataire en a fourni une ; elle vaut null sinon. consent_url_expires_at vaut null sauf si le prestataire donne une échéance, et null ne signifie pas que l'adresse n'expire jamais. Le temps ne change rien : aucun state ne change, et aucun montant réservé n'est libéré, parce qu'un délai s'est écoulé.
consent_url est une capacité au porteur : quiconque la détient peut ouvrir la page de consentement. Ne la stockez pas, ne la journalisez pas, et redemandez-en une plutôt que de réutiliser une ancienne. La réponse porte Cache-Control: no-store, et l'endpoint ne prend pas d'Idempotency-Key : une clé envoyée est ignorée, et rien n'est enregistré ni rejoué.
Six appels par minute, par application OAuth et par lot. Au-delà, l'appel est refusé par un 429 rate_limited, avec l'en-tête Retry-After en secondes : attendez ce délai avant de réessayer. Rien n'est fait, et le prestataire n'est pas interrogé. Chaque appel qui atteint le lot compte, un refus 422 compris ; un 404 ne compte pas. Les autres lots, et les autres applications, sont comptés à part. Pour suivre l'issue du consentement, lisez GET /api/v1/payment_batches/{id} ou attendez payment_batch.updated, plutôt que d'appeler consent_session en boucle : demandez une adresse quand le titulaire du compte doit ouvrir la page.
Les refus des écritures
| Statut | code | Quand |
|---|---|---|
422 | validation_failed | L'Idempotency-Key manque là où elle est exigée ; expected_version manque là où il est exigé ou ne se lit pas comme un entier ; un champ du corps est refusé - instructions vide ou qui n'est pas une liste d'objets, une ligne dans une autre devise que le lot ou que sa facture, un IBAN mal formé, un channel inconnu, un bank_account_id absent, une execution_date qui n'est pas au format AAAA-MM-JJ ; sur submit_for_approval, un lot sans instruction ou dont une instruction n'est plus valide ; sur submit, une réservation refusée, ou un lot que Scribee refuse avant tout envoi, qui passe alors à failed avec submission_refused_by à local. details nomme le champ, et une ligne s'y écrit instructions[0] pour la première |
422 | invalid_argument | bank_account_id ou un invoice_document_id ne désigne pas un enregistrement de l'entreprise du lot. Ce refus ne porte pas de details |
422 | batch_not_submittable | Le lot n'est pas dans l'état que l'opération exige : PATCH hors de draft, une transition depuis un autre état que son état de départ, submit sur un lot qui n'est pas approved, qui porte déjà une tentative, qu'une autre requête est en train de remettre, ou dont le channel est sepa_file ; consent_session sur un lot qui ne porte encore aucune tentative de remise, ou dont le channel est sepa_file. Ce refus ne porte pas de details ; message dit la cause |
422 | operation_failed | Sur submit, aucun canal n'est disponible pour ce lot. Rien n'a été envoyé |
409 | stale_version | expected_version ne correspond plus à la version du lot. Rien n'a été écrit ni envoyé ; details.current_version porte la version actuelle et details.payment_batch le lot |
409 | idempotency_key_reuse | La même Idempotency-Key accompagne une requête différente |
409 | idempotency_request_in_progress | Un appel portant la même Idempotency-Key est encore en cours |
429 | rate_limited | Sur consent_session, plus de six appels en une minute par la même application sur le même lot. Rien n'a été fait ; réessayez après le délai de l'en-tête Retry-After, en secondes |
Générer et télécharger le fichier SEPA
Un lot sepa_file quitte Scribee sous la forme d'un fichier de virements SEPA au format pain.001, que vous transmettez vous-même à votre banque. POST /api/v1/payment_batches/{id}/sepa_export le génère ; GET /api/v1/payment_batches/{id}/sepa_export le lit et le sert.
Un fichier généré, téléchargé ou remis à votre banque ne signifie pas que les virements ont été exécutés. Aucune de ces deux opérations ne rend compte de ce que la banque a fait, et aucune n'enregistre le paiement d'une facture. Le lot passe à submitted une fois la remise du fichier finalisée, et n'en sort que par la confirmation du règlement de ses instructions : Scribee ne reçoit pas de réponse de la banque sur un fichier SEPA.
Générer le fichier
curl -X POST https://app.scribee.tech/api/v1/payment_batches/6100/sepa_export \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Idempotency-Key: f0a2c518-4b73-49de-9c21-3e8a5d70b1c9"
L'en-tête Idempotency-Key est exigé. Le lot doit être approved et son channel doit valoir sepa_file. La génération engage la remise du lot par les mêmes contrôles que le centre de paiement - approbation, version, réservation, tentative unique : une fois l'appel accepté, le lot porte un submitted_at et ses instructions ne peuvent plus être remises une seconde fois.
Le corps est facultatif. Il peut porter expected_version, la version du lot telle que vous l'avez lue :
{ "expected_version": 6 }
Sans expected_version, aucune version n'est contrôlée. Avec, un lot qui a changé depuis votre lecture est refusé par un 409 stale_version et aucun fichier n'est généré. Une valeur qui ne se lit pas comme un entier est refusée par un 422 validation_failed, avec details.expected_version.
La réponse est un 202 portant la ressource d'export, y compris pour un lot dont l'export a déjà été demandé : l'appel répond alors avec l'export existant, quelle que soit la version envoyée, et n'en génère jamais un second. La génération elle-même change la version du lot : une fois l'export créé, renvoyer l'appel avec la version lue avant la génération répond donc cet export, et non un 409. Rejouer la même Idempotency-Key renvoie la réponse enregistrée.
{
"data": {
"id": 4400,
"payment_batch_id": 6100,
"state": "generating",
"progress": 100,
"retryable": false,
"started_at": "2026-08-27T10:05:40+02:00",
"finished_at": "2026-08-27T10:05:40+02:00",
"format": "pain.001.001.09",
"filename": "sepa-20260829-SCB4F1A9C07E2B84D5A9E36C1F0B7D2A845.xml",
"byte_size": 4812,
"sha256": "9f2c4e71a0b3d58e6c17f2a94b0e3d8c5a61f7e20b94c3d18e5a7f06c2b94d31",
"generated_at": "2026-08-27T10:05:40+02:00",
"served_count": 0,
"first_served": null,
"last_served": null
}
}
progress, started_at et finished_at décrivent la production du fichier, et non sa remise : seul state dit si le fichier est téléchargeable. retryable vaut toujours false.
Attendre le fichier
Interrogez GET /api/v1/payment_batches/{id}/sepa_export sans demander de XML : il répond la même ressource JSON. state vaut generating tant que la remise du fichier n'est pas finalisée, puis available - le lot est alors submitted. Ce sont ses deux seules valeurs. Le GET ne génère jamais de fichier : sur un lot dont l'export n'a jamais été demandé, il répond 404.
Télécharger le fichier
curl https://app.scribee.tech/api/v1/payment_batches/6100/sepa_export \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Accept: application/xml" \
-o sepa.xml
Avec Accept: application/xml et un state à available, la réponse est le fichier lui-même, en pièce jointe nommée d'après filename. Avant cela, la même requête répond un 200 portant la ressource JSON : vérifiez le Content-Type de la réponse avant de l'enregistrer comme fichier. Seul un 200 porte du XML : une erreur répond toujours en JSON, même avec Accept: application/xml.
Une fois available, le fichier ne change plus : ses octets, son sha256 et son generated_at sont figés. Comparez sha256 à l'empreinte SHA-256 du fichier reçu - c'est ce qui prouve que le fichier transmis à votre banque est celui que Scribee a produit. Un fichier dont les octets ne correspondent plus à sha256 n'est jamais servi.
Savoir quand le fichier a été servi
Chaque fois que les octets du fichier sont servis - téléchargés depuis le centre de paiement Scribee, ou par GET /api/v1/payment_batches/{id}/sepa_export avec Accept: application/xml -, Scribee l'enregistre. La ressource d'export le publie dans trois champs, présents dans toutes ses réponses, celle du POST comprise :
| Champ | Contenu |
|---|---|
served_count | Le nombre de fois où le fichier a été servi, tous canaux confondus ; 0 s'il ne l'a jamais été |
first_served | Le premier téléchargement, ou null si le fichier n'a jamais été servi |
last_served | Le dernier téléchargement, ou null si le fichier n'a jamais été servi. C'est le même que first_served quand le fichier n'a été servi qu'une fois |
first_served et last_served portent chacun :
| Champ | Contenu |
|---|---|
served_at | La date et l'heure où le fichier a été servi |
channel | web pour un téléchargement depuis le centre de paiement Scribee, api pour un téléchargement par cette API |
served_to | À qui le fichier a été servi, tel qu'il se nommait à ce moment : sur web, le prénom et le nom de l'utilisateur, ou, s'il n'a renseigné ni l'un ni l'autre, un libellé fixe qui ne l'identifie pas, dans la langue par défaut de la plateforme (le français : « Utilisateur sans nom ») ; sur api, le nom de l'application API. Ce n'est jamais une adresse e-mail |
Après un téléchargement depuis le centre de paiement puis un autre par l'API, la ressource se lit ainsi :
{
"data": {
"id": 4400,
"payment_batch_id": 6100,
"state": "available",
"progress": 100,
"retryable": false,
"started_at": "2026-08-27T10:05:40+02:00",
"finished_at": "2026-08-27T10:05:40+02:00",
"format": "pain.001.001.09",
"filename": "sepa-20260829-SCB4F1A9C07E2B84D5A9E36C1F0B7D2A845.xml",
"byte_size": 4812,
"sha256": "9f2c4e71a0b3d58e6c17f2a94b0e3d8c5a61f7e20b94c3d18e5a7f06c2b94d31",
"generated_at": "2026-08-27T10:05:40+02:00",
"served_count": 2,
"first_served": {
"served_at": "2026-08-27T11:02:13+02:00",
"channel": "web",
"served_to": "Claire Dupont"
},
"last_served": {
"served_at": "2026-08-28T09:14:50+02:00",
"channel": "api",
"served_to": "Compta Connect"
}
}
}
Servi signifie seulement que les octets du fichier ont été envoyés dans une réponse HTTP à cet utilisateur ou à cette application. Cela ne prouve ni que le fichier a été reçu, ni qu'il a été remis ou transmis à votre banque, ni que la banque a exécuté les virements. Seuls le state du lot et le status de ses instructions rendent compte de ce que la banque a fait.
Télécharger le fichier ne change rien d'autre : ni le lot, ni ses instructions, ni l'export, ni le paiement d'une facture. Ses octets, son sha256 et son generated_at restent ceux publiés. Répéter le téléchargement sert le même fichier et incrémente served_count à chaque fois. Ne sont pas comptés : la lecture de la ressource JSON, un 404, un refus operation_failed, ni un export encore generating. Si un téléchargement ne peut pas être enregistré, le fichier n'est pas servi : la réponse est une erreur, jamais le fichier.
Le scope exigé
Les deux opérations exigent le scope write, y compris le GET : le fichier porte les IBAN complets des bénéficiaires, que la surface JSON ne publie jamais. Un token qui ne porte que read reçoit un 403.
Les refus
| Statut | code | Quand |
|---|---|---|
422 | validation_failed | Le POST n'a pas d'Idempotency-Key ; ou le lot échoue à la validation métier pain.001, et details.base porte le diagnostic enregistré : chaque règle en échec, suivie de ce qu'elle vise, batch ou l'end_to_end_id d'une instruction ; ou une instruction ne peut pas réserver le montant de sa facture, et details est indexé payment_instructions.<id>, avec pour valeur already_reserved, exceeds_remaining_due ou currency_mismatch |
422 | validation_failed | expected_version ne se lit pas comme un entier ; details.expected_version le dit |
422 | batch_not_submittable | Le lot n'est pas approved, son channel est hosted_consent, sa tentative de remise s'est terminée sans fichier, ou une tentative de remise est toujours en cours sans avoir encore produit son export. Ce refus ne porte pas de details |
422 | operation_failed | Sur le GET avec Accept: application/xml : le fichier conservé a disparu, ou ne correspond plus à son sha256 |
409 | stale_version | expected_version ne correspond plus à la version du lot, et aucun export n'existe encore. Rien n'a été généré ; details.current_version porte la version actuelle et details.payment_batch le lot tel que GET /api/v1/payment_batches/{id} le publie |
409 | idempotency_key_reuse | La même Idempotency-Key accompagne une requête différente |
409 | idempotency_request_in_progress | Un appel portant la même Idempotency-Key est encore en cours |
Une tentative de remise toujours en cours se reconnaît à son message :
{
"error": "unprocessable_entity",
"code": "batch_not_submittable",
"message": "Une tentative de remise de ce lot de paiement est toujours en cours ; cet appel n'a rien généré. Relisez l'export dans quelques instants."
}
Renvoyez l'appel un peu plus tard : dès que cette tentative a produit son export, le POST répond un 202 avec lui.
Sur un 409 stale_version, relisez le lot depuis details, vérifiez qu'il doit toujours être remis, puis renvoyez l'appel avec details.current_version comme expected_version.
Un 404 dit que le lot n'est pas atteignable par vos habilitations ou, sur le GET, qu'aucun export n'a jamais été demandé pour ce lot.
Un refus 422 ne consomme pas la Idempotency-Key. Il ne rend pas pour autant chaque lot à nouveau générable. Un refus de réservation laisse le lot approved, sans tentative enregistrée : corrigez la cause et renvoyez l'appel. Un échec de la validation pain.001 est définitif : le lot passe à failed, avec submission_refused_by à local, et un nouvel appel répond batch_not_submittable.
Les erreurs
| Statut | error | Quand |
|---|---|---|
400 | bad_request | Un page qui n'est pas un entier supérieur ou égal à 1, ou une page au-delà de la dernière page d'une collection non vide |
403 | forbidden | Le token ne porte pas le scope exigé - read, ou write sur les écritures des lots, sur sepa_export et sur les POST de settlement -, votre client OAuth n'a pas d'habilitation sur ce workspace, ou le rapprochement bancaire y est désactivé |
404 | not_found | L'entreprise, le lot, l'instruction ou la suggestion n'est pas atteignable par vos habilitations |
Une page au-delà de la fin :
{
"error": "bad_request",
"message": "Le numéro de page dépasse le nombre de pages disponibles"
}
Un page qui n'est pas un entier valide porte le message "Le numéro de page doit être un entier supérieur ou égal à 1". Sur une collection vide, aucun numéro de page ne déborde : la réponse est un 200 avec une collection vide.
Sur les chemins par identifiant, l'atteignabilité est tranchée avant la fonctionnalité. Un lot ou une instruction que vos habilitations ne couvrent pas répond 404, jamais 403, même si le rapprochement bancaire est désactivé dans son workspace. Un 403 sur ces chemins ne confirme donc jamais qu'un identifiant existe hors de vos habilitations.
{
"error": "not_found",
"message": "La ressource demandée est introuvable"
}
Référence API
- Référence API : lister les lots de paiement
- Référence API : lire un lot de paiement
- Référence API : créer un lot de paiement en brouillon
- Référence API : modifier un lot de paiement en brouillon
- Référence API : soumettre un lot de paiement à approbation
- Référence API : approuver un lot de paiement
- Référence API : refuser l'approbation d'un lot de paiement
- Référence API : remettre un lot de paiement à son canal
- Référence API : reprendre le consentement d'un lot de paiement
- Référence API : lister les instructions d'un lot
- Référence API : lire une instruction de paiement
- Référence API : lire les suggestions de règlement d'un lot
- Référence API : chercher les opérations qui ont pu régler une instruction
- Référence API : écarter une suggestion de règlement
- Référence API : confirmer une suggestion de règlement
- Référence API : confirmer l'opération qui a réglé une instruction
- Référence API : annuler le rapprochement d'une instruction
- Référence API : déclarer une instruction non exécutée
- Référence API : générer le fichier SEPA d'un lot
- Référence API : lire ou télécharger le fichier SEPA d'un lot