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.

JSON
"receivable":{17 items
"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"
}
{
  "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

ChampTypeDescription
objectstringToujours "receivable".
buyer_idstringEntreprise acheteuse (cmp_…) pour lequel la créance est calculée.
merchant_idstringMarchand créancier.
currencystringDevise commune à toutes les factures incluses (ISO 4217 minuscules). Erreur si les factures sont multi-devises.
balance_excluding_taxintegerSolde HT total dû, en centimes. Toujours ≥ 0.
balance_including_taxintegerSolde TTC total dû, en centimes. Toujours ≥ 0.
balance_due_excluding_taxintegerPortion HT du solde dont la date d'échéance est dépassée. Toujours ≥ 0.
balance_due_including_taxintegerPortion TTC du solde échu. Toujours ≥ 0.
balance_disputed_excluding_taxintegerPart HT du solde rattachée à des factures actuellement contestées.
balance_disputed_including_taxintegerPart TTC du solde rattachée à des factures actuellement contestées.
balance_due_disputed_excluding_taxintegerPart HT à la fois échue et contestée.
balance_due_disputed_including_taxintegerPart TTC à la fois échue et contestée.
balance_due_undisputed_excluding_taxintegerPart HT échue non contestée.
balance_due_undisputed_including_taxintegerPart TTC échue non contestée.
oldest_due_datedate | nullÉchéance la plus ancienne parmi les factures ouvertes avec une due_date.
latest_due_datedate | nullÉchéance la plus récente parmi les factures ouvertes avec une due_date.
computed_atdatetimeHorodatage du calcul.

Périmètre de calcul

Le calcul n'inclut que les factures satisfaisant simultanément les deux conditions suivantes.

ChampValeur requiseRaison
statusissued, sent, receivedInclut les documents émis, qu’ils aient ou non déjà été envoyés ou réceptionnés.
settlement_status≠ paidExclut 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.

Toutes les devises doivent être identiques Si les factures actives d'un acheteur utilisent des devises différentes, le calcul échoue avec une erreur 422. Les factures doivent être homogènes en devise pour qu'un receivable puisse être calculé.

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_*.

Le receivable ne décide pas quoi recouvrer Ces balances sont analytiques. Un processus peut choisir de relancer tout le solde échu, uniquement la partie non contestée, ou traiter séparément la partie contestée. Ormuz n'applique pas une politique universelle de suspension du recouvrement.

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 :

HTTP
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 émisEffet supplémentaire
Solde TTC franchit la limite à la haussecredit_limit.exceededLa 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.approachingAucun. 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

JSON
{1 item
"company":"platform.company"
}
{
  "company": "platform.company"
}

Sortie

JSON
{1 item
"receivable":"platform.receivable"
}
{
  "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

JSON
{6 items
"company":"platform.company"
"amount":120000
"currency":"eur"
"invoice":"platform.invoice"
"order":"platform.order"
"reference":"FAC-2026-00042"
}
{
  "company": "platform.company",
  "amount": 120000,
  "currency": "eur",
  "invoice": "platform.invoice",
  "order": "platform.order",
  "reference": "FAC-2026-00042"
}

Sortie

JSON
{2 items
"selected_route":"exact_match"
"allocation_proposal":{3 items
"type":"common.receivable_allocation"
"amount":120000
"currency":"eur"
}
}
{
  "selected_route": "exact_match",
  "allocation_proposal": {
    "type": "common.receivable_allocation",
    "amount": 120000,
    "currency": "eur"
  }
}
RouteSignification
exact_matchLe montant correspond exactement au total des factures candidates.
underpaymentLe montant est inférieur au total des factures — paiement partiel.
overpaymentLe montant dépasse le total des factures candidates.
ambiguousPlusieurs combinaisons de factures correspondent au montant — arbitrage nécessaire.
unmatchedAucune 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énementDéclencheur
receivable.updatedLe solde a changé lors d'un refresh du snapshot (avant ≠ après). Contient un diff before/after.
receivable.zeroLe solde est passé de > 0 à 0 lors d'un refresh.
receivable.overdueTimer : déclenché une fois dès que balance_due_including_tax > 0 (au moins une facture échue).
receivable.due_date_stage_reachedTimer : 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.