Skip to main content

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:

  1. Claim-managed (what BNPL/loan examples use): the client calls create_claims / update_claims / resolve_claims and owns the claim lifecycle.
  2. 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 type ACCOUNT_INVOICE automatically (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 conceptPlatform entity
SubscriberAccount (created upfront via create_accounts)
Contract / subscription lineProduct (e.g. one per mobile line or meter)
Monthly invoiceInvoice Ledger Entry → platform-created ACCOUNT_INVOICE claim
Late/dunning feeFee Ledger Entry (attached to the invoice via context)
Payment received by clientPayment Ledger Entry, or match_account_payment
Correction / goodwill creditAdjustment / Discount Ledger Entry
Failed direct debitChargeback Ledger Entry
Billing disputepause_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

  1. 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.
  2. 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)?
  3. What pauses dunning? Disputes, promised payments, vulnerable-customer flags — map each to pause_journeys/resume_journeys triggers and decide who fires them.
  4. 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.
  5. How are chargebacks and corrections communicated? Volume matters: heavy direct-debit clients need the chargeback flow tested early.

This example focuses on what to model; the step-by-step mechanics of each API call are covered by the generic use cases: