Modelling Example: B2B Invoices
This document shows how to map a business-to-business receivables client — a wholesaler, logistics provider, or factoring company collecting commercial invoices — onto the platform. The client described here ("FacturaPro") is fictional. Companion examples: BNPL, Personal Loan, Recurring Invoices, Debt Buyer, Revolving Credit.
B2B collections differ from consumer collections less in entities than in dynamics:
- The debtor is a company. The schema supports this directly:
Debtor.type: "legal"withcompanyNamerequired — contacts are roles (accounts payable), not individuals. - Non-payment is usually a dispute or a cash-flow negotiation, not a default. Short payment, damaged goods, missing PO numbers. The core workflow is dispute → adjustment → promise → payment, and the model has a first-class tool for the promise step.
- Few accounts, large amounts, partial everything. Partial payments, partial credit notes, partial disputes — the fee/credit mechanics get used constantly.
Entity mapping
| B2B concept | Platform entity / mechanism |
|---|---|
| Business customer | Account, debtor type: "legal" + companyName |
| Contract / customer relationship | Product (optional; useful when one customer has several) |
| Overdue invoice | Claim (one per invoice, ref = invoice number) |
| Credit note | credit_claims (partial or full) |
| Dispute | pause_journeys (+ resolution via credit or resume) |
| Payment commitment | create_promises_to_pay (amount, currency, dueDate) |
| Withdrawn/cancelled invoice | resolve_claims reason CLAIM_INVALIDATED / CLAIM_DISCARDED |
| Late-payment interest (B2B statutory) | named fees entries via debit_claims |
Promises to pay are the mechanism the consumer examples never needed: a lightweight,
trackable commitment — "we will pay €X by date D" — attached to a claim. The platform tracks
the outcome and emits event.promiseToPay.resolved / event.promiseToPay.expired, which the
strategy consumes: kept promise → de-escalate; expired promise → escalate. This is exactly the
cadence of B2B collections calls, where every conversation ends in a promise, and it is far
lighter than an Instalment Plan (no schedule, no mandate — just amount and date).
Fictional client: "FacturaPro"
Assumed policies:
- Wholesale distributor; invoices €2,000–€250,000, payment terms 30–60 days.
- Invoices are placed at due date + 14 days. Statutory B2B late-payment interest and a fixed recovery fee apply.
- Disputes are frequent (~15% of overdue invoices) and must silence dunning immediately — dunning a disputed invoice damages the commercial relationship.
- Escalation ladder: reminder → account-manager call (promise expected) → formal notice → legal handover.
Worked example: Almacenes Rivera
Almacenes Rivera (a retail chain) has three overdue invoices totalling €78,000.
- Account = Almacenes Rivera, primary debtor
{ "type": "legal", "companyName": "Almacenes Rivera S.A.", "contactInformation": { /* AP dept */ } }. - Claims = one per invoice:
FP-INV-10231(€30k),FP-INV-10298(€28k),FP-INV-10344(€20k), each with statutory interest and the recovery fee as namedfees. Account-level strategy contacts Rivera once about the full position — but each invoice keeps its own lifecycle, which is essential because they diverge immediately:
Invoice 10298 is disputed (short delivery claimed). FacturaPro pauses dunning on it
(pause_journeys) while the other two continue. The dispute resolves with an agreed €4,000
credit note:
// POST /v1/{clientId}/credit_claims
{
"FP-INV-10298": { "amount": 400000, "fees": 0 },
}
then resume_journeys puts the corrected invoice back into the flow. Had the invoice been
withdrawn entirely, resolve_claims with CLAIM_INVALIDATED would close it without
pretending it was collected.
Alternative for long-running disputes: split the invoice
instead of pausing all of it — credit the disputed €4,000 out of FP-INV-10298 and place it
as its own claim carrying relatedClaims: [{ "type": "SPLIT_FROM", "claimReference": "FP-INV-10298" }]. The undisputed €24,000 keeps its dunning journey while only the split
claim sits paused, and the lineage stays queryable.
Invoices 10231 and 10344 — the collections call. Rivera's finance director commits to paying the older invoice this month and the rest next month. That is two promises:
// POST /v1/{clientId}/create_promises_to_pay
{
"FP-INV-10231": {
"amount": 3000000,
"currency": "EUR",
"dueDate": "2026-08-15",
},
"FP-INV-10344": {
"amount": 2000000,
"currency": "EUR",
"dueDate": "2026-09-15",
},
}
The strategy holds escalation while a promise is open. If event.promiseToPay.resolved fires
(payment arrived), the next step de-escalates; on event.promiseToPay.expired, the formal
notice goes out — no human has to remember to follow up.
Partial payment without a promise: if Rivera simply wires €10,000 against invoice 10344,
credit_claims reduces it; the claim stays open for the remainder.
Discovery questions for a real B2B client
- What does their dispute process look like, and who decides? Map dispute-open →
pause_journeys, dispute-resolved → credit note +resume_journeys. Volume decides whether this is API-automated or backoffice-manual. - Are promises to pay part of their collections culture? If their team already works
call-and-promise cycles, wire
create_promises_to_payand the promise events into the escalation ladder from day one — it is the highest-leverage feature for this profile. - How do credit notes flow? From their ERP automatically (
credit_claimsintegration) or manually? Partial credits against fees vs principal need the named-fee semantics agreed. - Statutory interest and recovery fees — jurisdiction-specific (e.g. EU Late Payment
Directive): fixed at placement or accruing (→
debit_claims, see the revolving example)? - When does legal handover happen, and what does it need? Typically an export of claim +
promise + dispute history; confirm
get_eventscovers the audit trail their lawyers expect.
Related use cases
This example focuses on what to model; the step-by-step mechanics of each API call are covered by the generic use cases:
- Authentication — obtaining the access token every request needs
- Create Claims — the mechanics of placing claims (single and batched)
- Register Payments — crediting claims for payments received on your side
- Resolve Claims — closing claims with the correct resolution reason
- Consolidate Claims — replacing claims with a consolidated one, with typed relations
- Webhook Validation — receiving platform events on your side