Modelling Example: Recurring Invoices (Telco/Utility)
This document shows how to map a subscription business — telco, utility, SaaS, insurance — onto the platform. The client described here ("ConectaTel") is fictional. Companion examples: BNPL and Personal Loan.
Recurring-invoice clients differ fundamentally from the credit examples: the debt is not a defaulted loan contract but an open, ongoing service relationship that keeps producing new invoices while old ones are in collection. This changes the integration mode itself.
The key decision: claim-managed vs ledger-managed integration
The platform supports two integration modes, and they must not be mixed for the same debt:
- Claim-managed (what BNPL/loan examples use): the client calls
create_claims/update_claims/resolve_claimsand owns the claim lifecycle. - Ledger-managed (this example): the client pushes Ledger Entries via
add_account_ledger_entries— invoices, fees, payments, adjustments, chargebacks, discounts — and the platform derives the claims. The platform turns each open Invoice Ledger Entry into a claim of typeACCOUNT_INVOICEautomatically (amount, due date, fees, and debtor are all computed from the ledger), and payment entries resolve them.
The import_claims endpoint documentation is explicit: "claims updated with this endpoint are
not managed by the Ledger; to update Claims related with the Ledger, use the Ledger related API
endpoints." Once an account is ledger-managed, all financial changes flow through ledger
entries — never through direct claim endpoints.
Why ledger-managed fits recurring billing: the debt position of a subscriber is a running statement (invoices − payments ± adjustments), not a fixed placed balance. Pushing the statement lines and letting the platform derive claims keeps both systems reconciled by construction.
Entity mapping
| Subscription concept | Platform entity |
|---|---|
| Subscriber | Account (created upfront via create_accounts) |
| Contract / subscription line | Product (e.g. one per mobile line or meter) |
| Monthly invoice | Invoice Ledger Entry → platform-created ACCOUNT_INVOICE claim |
| Late/dunning fee | Fee Ledger Entry (attached to the invoice via context) |
| Payment received by client | Payment Ledger Entry, or match_account_payment |
| Correction / goodwill credit | Adjustment / Discount Ledger Entry |
| Failed direct debit | Chargeback Ledger Entry |
| Billing dispute | pause_journeys / resume_journeys on the affected scope |
Unlike the credit examples, the Account is created first (with debtors, currency, and
products) and lives as long as the subscription; claims come and go beneath it as invoices are
issued and settled. Note that the platform intentionally does not auto-create accounts or
products from ACCOUNT_INVOICE claims — the account must exist before ledger entries arrive.
Fictional client: "ConectaTel"
Assumed policies:
- Mobile subscriptions, ~€40/month, invoiced on the 1st, due on the 15th.
- Unpaid invoices enter dunning at due date + 5 days, with a €5 dunning fee per reminder.
- Service is throttled after 2 unpaid invoices, terminated after 4 — but the customer relationship continues: tone matters, and a disputed invoice must pause dunning without cancelling it.
- Direct debit is the main payment method, so failed collections (chargebacks) are common.
Worked example: Laura's mobile plan
Laura subscribes to a €40/month plan. She misses the March and April invoices.
Setup: ConectaTel creates the account once (subscriber data, currency, product
CT-LINE-8801 for the line) via create_accounts.
March invoice unpaid — ConectaTel pushes the invoice as a ledger entry:
// POST /v1/{clientId}/add_account_ledger_entries
{
"ACC-LAURA-001": [
{
"ledgerEntryReference": "CT-INV-2026-03-8801",
"invoiceDetails": {
"amount": 4000, // cents
"dueDate": "2026-03-15",
"paymentReference": "CT-PAY-8801",
},
"context": { "productReference": "CT-LINE-8801" },
},
],
}
The platform creates the corresponding ACCOUNT_INVOICE claim itself — ConectaTel never calls
create_claims. The dunning fee is a separate Fee Ledger Entry referencing the same context,
and it surfaces as a fees entry on the derived claim.
April invoice unpaid — same flow; the account now has two open invoice claims plus fees. Collections strategy runs at account level: Laura gets one communication about her total balance, not one per invoice (see the account-level collections overview).
Partial payment — Laura pays €60 against a €90 balance (2×€40 + 2×€5 fees). One call, and the platform distributes it:
// POST /v1/{clientId}/match_account_payment
{
"ACC-LAURA-001": {
"totalAmount": 6000,
"currency": "EUR",
"matchStrategy": "ORDERED_INVOICES_WITH_FEES_THEN_ACCOUNT_ENTRIES",
"providerName": "trustly",
"trackingId": "3889445415",
},
}
Available strategies: ORDERED_LEDGER_ENTRIES, ORDERED_INVOICES_WITH_FEES_THEN_ACCOUNT_ENTRIES,
ACCOUNT_ENTRIES_THEN_ORDERED_INVOICES_WITH_FEES, CUSTOM_ORDERED_FEES (with
context.feeLedgerEntriesOrder). Which strategy is correct is a client policy question —
oldest-invoice-first vs fees-first materially changes what remains outstanding.
Failed direct debit: if a matched payment later bounces, a Chargeback Ledger Entry reverses it and the affected claims reopen.
Dispute: Laura disputes the April invoice. ConectaTel calls pause_journeys scoped to the
disputed debt; if the dispute is upheld, a Discount/Adjustment Ledger Entry reduces or cancels
the invoice (the discount entry targets the specific invoice via its
context.ledgerEntryReference); otherwise resume_journeys continues dunning.
Discovery questions for a real recurring-invoice client
- Ledger-managed or claim-managed? If the client can emit statement lines (invoices/payments/adjustments), ledger-managed keeps reconciliation automatic. If their billing system can only export "open overdue invoices", claim-managed with one claim per invoice (BNPL Phase-1 style) also works — but pick one mode per account and stick to it.
- Which payment-matching strategy reflects their allocation policy? Also: do payments
arrive through the platform (landing page) or through the client's own rails
(
match_account_payment/ Payment Ledger Entries)? - What pauses dunning? Disputes, promised payments, vulnerable-customer flags —
map each to
pause_journeys/resume_journeystriggers and decide who fires them. - When does the relationship switch from "customer in arrears" to "terminated debtor"? After termination the remaining balance behaves like a placed debt (final invoice claim, possibly a Receive Instalment Plan as treatment) — the credit examples apply from there.
- How are chargebacks and corrections communicated? Volume matters: heavy direct-debit clients need the chargeback flow tested early.
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
- Payment Reversal (Chargeback) — restoring and reactivating debt when a payment bounces
- Resolve Claims — closing claims with the correct resolution reason
- Webhook Validation — receiving platform events on your side