Créance (receivable)
Un receivable est une vue calculée du montant total dû par un acheteur à un marchand, agrégé sur l'ensemble de ses factures émises et non soldées. Ce n'est pas un objet persisté : il est recalculé à la demande depuis les factures actives et les paiements déjà alloués.
Rôle
Le receivable répond à une question simple : combien cet acheteur doit-il encore à ce marchand, et quelle part est déjà échue ? Il agrège toutes les factures émises dont le règlement n'est pas encore complet, déduit les avoirs et les paiements déjà appliqués, et expose le solde net.
Le receivable est le point d'entrée naturel pour le rapprochement de paiements entrants : un montant reçu d'un acheteur est comparé à son receivable pour identifier les factures à solder.
Structure
Le receivable n'a pas d'identifiant propre — il est identifié par le couple (buyer_id, merchant_id). Chaque appel retourne le calcul à l'instant computed_at.
{
"object": "receivable",
"buyer_id": "cmp_3a8f1d9c2b4e7f6a",
"merchant_id": "mer_1a2b3c4d5e6f7a8b",
"currency": "eur",
"balance_excluding_tax": 200000,
"balance_including_tax": 240000,
"balance_due_excluding_tax": 83334,
"balance_due_including_tax": 100000,
"balance_disputed_excluding_tax": 25000,
"balance_disputed_including_tax": 30000,
"balance_due_disputed_excluding_tax": 25000,
"balance_due_disputed_including_tax": 30000,
"balance_due_undisputed_excluding_tax": 58334,
"balance_due_undisputed_including_tax": 70000,
"oldest_due_date": "2026-05-31",
"latest_due_date": "2026-07-31",
"computed_at": "2026-06-17T14:30:00.000Z"
}Champs
| Champ | Type | Description |
|---|---|---|
object | string | Toujours "receivable". |
buyer_id | string | Entreprise acheteuse (cmp_…) pour lequel la créance est calculée. |
merchant_id | string | Marchand créancier. |
currency | string | Devise commune à toutes les factures incluses (ISO 4217 minuscules). Erreur si les factures sont multi-devises. |
balance_excluding_tax | integer | Solde HT total dû, en centimes. Toujours ≥ 0. |
balance_including_tax | integer | Solde TTC total dû, en centimes. Toujours ≥ 0. |
balance_due_excluding_tax | integer | Portion HT du solde dont la date d'échéance est dépassée. Toujours ≥ 0. |
balance_due_including_tax | integer | Portion TTC du solde échu. Toujours ≥ 0. |
balance_disputed_excluding_tax | integer | Part HT du solde rattachée à des factures actuellement contestées. |
balance_disputed_including_tax | integer | Part TTC du solde rattachée à des factures actuellement contestées. |
balance_due_disputed_excluding_tax | integer | Part HT à la fois échue et contestée. |
balance_due_disputed_including_tax | integer | Part TTC à la fois échue et contestée. |
balance_due_undisputed_excluding_tax | integer | Part HT échue non contestée. |
balance_due_undisputed_including_tax | integer | Part TTC échue non contestée. |
oldest_due_date | date | null | Échéance la plus ancienne parmi les factures ouvertes avec une due_date. |
latest_due_date | date | null | Échéance la plus récente parmi les factures ouvertes avec une due_date. |
computed_at | datetime | Horodatage du calcul. |
Périmètre de calcul
Le calcul n'inclut que les factures satisfaisant simultanément les deux conditions suivantes.
| Champ | Valeur requise | Raison |
|---|---|---|
status | issued, sent, received | Inclut les documents émis, qu’ils aient ou non déjà été envoyés ou réceptionnés. |
settlement_status | ≠ paid | Exclut les factures entièrement réglées ; unpaid et partially_paid restent dans le solde ouvert. |
Pour chaque facture incluse, le montant déjà alloué via des allocations de paiement est déduit. Les avoirs (type: "credit_note") contribuent avec un montant négatif — ils réduisent le solde global. Lorsqu'un avoir est rattaché à une facture source, il suit cette facture pour les axes d'échéance et de litige : l'ensemble facture + avoirs est lu comme un même groupe économique.
Solde échu
Les champs balance_due_* isolent la portion du solde dont la date d'échéance (due_date) est strictement antérieure à l'instant du calcul. Une facture sans due_date est incluse dans le balance_* global mais n'alimente jamais le balance_due_*. Un avoir rattaché hérite du bucket temporel de sa facture source : son absence dedue_date propre ne l'empêche donc pas de réduire une créance déjà échue.
Les champs oldest_due_date et latest_due_date reflètent la fenêtre d'échéance des factures ouvertes — ils permettent de calculer l'ancienneté du retard et de positionner des relances dans le temps.
Litiges
Une facture couverte par au moins un litige ouvert porte disputed = true. Les balances balance_disputed_*isolent la contribution nette de ces factures et de leurs avoirs rattachés. Une même facture couverte par plusieurs litiges ouverts n'est comptée qu'une seule fois.
Les balances balance_due_disputed_* isolent la part échue contestée etbalance_due_undisputed_* la part échue non contestée. La relation est toujours : balance_due_undisputed_* = balance_due_* - balance_due_disputed_*.
Snapshot et mise à jour
En parallèle du calcul à la demande, la plateforme conserve le dernier solde financier global connu et le rafraîchit automatiquement après les mutations financières pertinentes. Une vérification périodique assure également la convergence si une mise à jour n'a pas été observée immédiatement.
Deux endpoints permettent d'agir sur ce cycle :
GET /v1/companies/cmp_3a8f/receivable POST /v1/companies/cmp_3a8f/receivable/refresh
L'endpoint GET retourne toujours un calcul frais. Le POST /refresh recalcule, met à jour le snapshot et émet receivable.updated si le solde a changé, ou receivable.zero si le solde est passé à zéro.
Limite de crédit
À chaque refresh du snapshot, la plateforme compare le solde courant à la limite de crédit active de l'acheteur. Deux seuils sont surveillés.
| Situation | Événement émis | Effet supplémentaire |
|---|---|---|
| Solde TTC franchit la limite à la hausse | credit_limit.exceeded | La company est suspendue (suspended: true) et l'événement company.suspended est émis avec reason: "credit_limit_exceeded". |
| Solde TTC atteint 80 % de la limite (sans la dépasser) | credit_limit.approaching | Aucun. Payload inclut approaching_ratio: 0.8. |
Ces événements sont émis une seule fois lors du franchissement — ils ne se répètent pas tant que le solde reste dans la même zone. La vérification n'a lieu qu'en cas de refresh : un refresh déclenché sans changement de solde ne réémet pas l'événement.
Dans les processus
fetch_receivable
Le helper fetch_receivable calcule le receivable courant d'une company et le retourne comme objet typé utilisable dans les étapes suivantes du processus.
Paramètre
{
"company": "platform.company"
}Sortie
{
"receivable": "platform.receivable"
}propose_payment_allocation
Ce node routeur est le point central du rapprochement entrant. Il reçoit un montant de paiement et une company, et cherche parmi les factures ouvertes la ou les factures à solder. Il route selon le résultat du matching.
Paramètres principaux
{
"company": "platform.company",
"amount": 120000,
"currency": "eur",
"invoice": "platform.invoice",
"order": "platform.order",
"reference": "FAC-2026-00042"
}Sortie
{
"selected_route": "exact_match",
"allocation_proposal": {
"type": "common.receivable_allocation",
"amount": 120000,
"currency": "eur"
}
}| Route | Signification |
|---|---|
exact_match | Le montant correspond exactement au total des factures candidates. |
underpayment | Le montant est inférieur au total des factures — paiement partiel. |
overpayment | Le montant dépasse le total des factures candidates. |
ambiguous | Plusieurs combinaisons de factures correspondent au montant — arbitrage nécessaire. |
unmatched | Aucune facture trouvée pour ce montant, cette company et cette devise. |
L'allocation_proposal produit en sortie est passé directement au node reconcile_payment pour appliquer le rapprochement, que la source soit un payment ou un psp_payment.
Autres usages
Le receivable peut être passé en paramètre optionnel à create_psp_payment pour associer le contexte de créance au paiement PSP créé. Depuis un agent IA, l'outil get_company_receivable expose le même calcul.
Événements
| Événement | Déclencheur |
|---|---|
receivable.updated | Le solde a changé lors d'un refresh du snapshot (avant ≠ après). Contient un diff before/after. |
receivable.zero | Le solde est passé de > 0 à 0 lors d'un refresh. |
receivable.overdue | Timer : déclenché une fois dès que balance_due_including_tax > 0 (au moins une facture échue). |
receivable.due_date_stage_reached | Timer : déclenché à chaque palier configuré (jours avant/après oldest_due_date). Contient days_from_due_date. |
Les événements timer (receivable.overdue et receivable.due_date_stage_reached) sont émis par le moteur de timers de la plateforme selon un calendrier configuré. Ils permettent de déclencher automatiquement des processus de relance ou d'escalade sans polling.
receivable.due_date_stage_reached inclut le champ days_from_due_date : une valeur négative indique un palier avant l'échéance (anticipation), une valeur positive indique un palier après (retard). La référence est oldest_due_date parmi les factures ouvertes.