Receivable ( receivable )
A receivable is a calculated view of the total amount a buyer owes a merchant, aggregated across all issued and unsettled invoices. It is not a persisted object: it is recalculated on demand from active invoices and already-allocated payments.
Role
The receivable answers a simple question: how much does this buyer still owe this merchant, and how much is already overdue? It aggregates all
invoices issued invoices whose settlement is not complete, subtracts credit notes and already-applied payments, and exposes the net balance.
The receivable is the natural entry point for matching incoming payments: an amount received from a buyer is compared with its receivable to identify invoices to settle.
Structure
The receivable has no identifier of its own — it is identified by the pair (buyer_id, merchant_id). Every call returns the calculation at 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"
}Fields
| Field | Type | Description |
|---|---|---|
object | string | Always "receivable". |
buyer_id | string | Buyer company (`cmp_…`) for which the receivable is calculated. |
merchant_id | string | Creditor merchant. |
currency | string | Currency shared by all included invoices (lowercase ISO 4217). Error when invoices use multiple currencies. |
balance_excluding_tax | integer | Total balance due excluding tax, in cents. Always ≥ 0. |
balance_including_tax | integer | Total balance due including tax, in cents. Always ≥ 0. |
balance_due_excluding_tax | integer | Excluding-tax portion of the balance past its due date. Always ≥ 0. |
balance_due_including_tax | integer | Including-tax portion of the overdue balance. Always ≥ 0. |
balance_disputed_excluding_tax | integer | Excluding-tax portion of the balance attached to currently disputed invoices. |
balance_disputed_including_tax | integer | Including-tax portion of the balance attached to currently disputed invoices. |
balance_due_disputed_excluding_tax | integer | Excluding-tax portion that is both overdue and disputed. |
balance_due_disputed_including_tax | integer | Including-tax portion that is both overdue and disputed. |
balance_due_undisputed_excluding_tax | integer | Excluding-tax overdue, undisputed portion. |
balance_due_undisputed_including_tax | integer | Including-tax overdue, undisputed portion. |
oldest_due_date | date | null | Oldest due date among open invoices with a `due_date`. |
latest_due_date | date | null | Latest due date among open invoices with a `due_date`. |
computed_at | datetime | Calculation timestamp. |
Calculation scope
time. The calculation includes only invoices satisfying both of the following conditions.
| Field | Required value | Reason |
|---|---|---|
status | issued, sent, received | Includes issued documents whether or not they have already been sent or received. |
settlement_status | ≠ paid | Excludes fully settled invoices; `unpaid` and `partially_paid` remain in the open balance. |
For every included invoice, amounts already allocated through payment allocations are subtracted. Credit notes (type: "credit_note") contribute a negative amount — they reduce the overall balance. When a credit note is attached to a source invoice, it follows that invoice for due-date and dispute axes: the invoice plus its credit notes are read as one economic group.
If a buyer's active invoices use different currencies, calculation fails with a 422 error. Invoices must be homogeneous in currency for a receivable to be calculated.
Overdue balance
The fields balance_due_* isolate the portion of the balance whose due date (due_date) is strictly before calculation time. An invoice without due_date is included in the global
balance_* balance but never contributes to the balance_due_*. An attached credit note inherits the time bucket of its source invoice: lacking its own
due_date does not prevent it from reducing an already-overdue receivable.
The fields oldest_due_date and latest_due_date reflect the due-date window of open invoices — allowing calculation of aging and positioning of reminders over time.
Disputes
An invoice covered by at least one open dispute
exposes disputed = true. The balances balance_disputed_*
isolate the net contribution of those invoices and attached credit notes. The same invoice covered by several open disputes is counted only once.
The balances balance_due_disputed_* isolate the overdue disputed portion and
balance_due_undisputed_* the overdue undisputed portion. The relationship is always: balance_due_undisputed_* = balance_due_* - balance_due_disputed_*.
These balances are analytical. A process may choose to pursue all overdue balance, only the undisputed part, or handle the disputed portion separately. Ormuz does not apply a universal policy for suspending collections.
Snapshot and update
Alongside on-demand calculation, the platform keeps the latest known overall financial balance and automatically refreshes it after relevant financial mutations. A periodic check also ensures convergence if an update was not observed immediately.
Two endpoints operate this lifecycle:
GET /v1/companies/cmp_3a8f/receivable POST /v1/companies/cmp_3a8f/receivable/refresh
L'endpoint GET always returns a fresh calculation. The
POST /refresh recalculates, updates the snapshot, and emits
receivable.updated when the balance changed, or
receivable.zero when the balance transitioned to zero.
Credit limit
On each snapshot refresh, the platform compares the current balance with the buyer's active credit limit . Two thresholds are monitored.
| Situation | Event emitted | Additional effect |
|---|---|---|
| Including-tax balance crosses the limit upward | credit_limit.exceeded | The company is suspended (suspended: true) and the event company.suspended is emitted with reason: "credit_limit_exceeded". |
| Including-tax balance reaches 80% of the limit without exceeding it | credit_limit.approaching | None. Payload includes approaching_ratio: 0.8. |
These events are emitted once per threshold crossing — they do not repeat while the balance stays in the same zone. The check runs only on refresh: a refresh without a balance change does not re-emit the event.
In processes
fetch_receivable
The helper fetch_receivable calculates a company's current receivable and returns it as a typed object usable by later process steps.
Parameter
{
"company": "platform.company"
}Output
{
"receivable": "platform.receivable"
}propose_payment_allocation
This router node is the central point of incoming reconciliation. It receives a payment amount and company and searches open invoices for one or more invoices to settle. It routes according to the matching result.
Main parameters
{
"company": "platform.company",
"amount": 120000,
"currency": "eur",
"invoice": "platform.invoice",
"order": "platform.order",
"reference": "FAC-2026-00042"
}Output
{
"selected_route": "exact_match",
"allocation_proposal": {
"type": "common.receivable_allocation",
"amount": 120000,
"currency": "eur"
}
}| Route | Meaning |
|---|---|
exact_match | The amount exactly matches the total of candidate invoices. |
underpayment | The amount is lower than the invoice total — partial payment. |
overpayment | The amount exceeds the total of candidate invoices. |
ambiguous | Several invoice combinations match the amount — arbitration is required. |
unmatched | No invoice found for this amount, company, and currency. |
The allocation_proposal output is passed directly to the node reconcile_payment to apply reconciliation, whether the source is a payment or a psp_payment.
Other uses
The receivable may be passed as an optional parameter to
create_psp_payment to associate receivable context with the created PSP payment. From an AI Agent, the tool get_company_receivable exposes the same calculation.
Events
| Event | Trigger |
|---|---|
receivable.updated | The balance changed during a snapshot refresh (before ≠ after). Contains a before/after diff. |
receivable.zero | The balance transitioned from > 0 to 0 during a refresh. |
receivable.overdue | Timer: triggered once when `balance_due_including_tax > 0` and at least one invoice is overdue. |
receivable.due_date_stage_reached | Timer: triggered at each configured threshold, days before/after `oldest_due_date`. Contains `days_from_due_date`. |
Timer events (receivable.overdue and
receivable.due_date_stage_reached) are emitted by the platform timer engine according to a configured schedule. They can automatically trigger reminder or escalation processes without polling.
receivable.due_date_stage_reached includes the field
days_from_due_date : a negative value indicates a threshold before due date, while a positive value indicates a threshold after due date. The reference is oldest_due_date among open invoices.