IFRS 15 for SaaS: one contract worked through all five steps
A customer signs in early January: an annual licence for €24,000, a data migration for €6,000, and €0.01 per API call billed monthly in arrears. You invoice €30,000 the same day. How much of that is January revenue? Depending on how you read the contract, either €9,375 plus usage or €2,500 plus usage. Neither figure appears on the invoice.
This article runs that one contract through the five steps of IFRS 15: identify the contract, identify the performance obligations, determine the transaction price, allocate it, and recognise revenue when or as each obligation is satisfied. All amounts are a made-up example. Nothing here replaces your accounting policy or a conversation with your auditor. The point is to show which judgements finance has to make and which data the billing system has to supply so those judgements can be applied automatically.
Steps 1 and 2: is the migration a separate promise?
Step 1 is rarely contentious. A signed order form with price, term and payment terms is a contract. It gets awkward when a master agreement, an order form and a side letter are signed with the same customer within days of each other and only make commercial sense together. You may have to combine them, which means your system needs to know which documents belong together.
Step 2 is where the real decision sits. A promise is a separate performance obligation if the customer can benefit from it on its own (or with resources readily available to them) and it is separately identifiable within the contract. The migration can plausibly go either way:
- Case A: the migration moves legacy data into a format the customer could use without your product, and third parties sell the same service. It's a distinct performance obligation.
- Case B: the "migration" is really tenant set-up without which the licence doesn't work. It isn't distinct. The €6,000 is extra consideration for the licence and is spread over the term. If the upfront fee gives the customer a material right, such as renewal without paying it again, the recognition period can even be longer than the contract.
The invoice line won't settle this. Sales calls both versions "onboarding", and the invoice shows a single €6,000 line either way. What matters is what's actually delivered, so make the call once per product in the catalogue, not once per invoice.
We treat the API fee here as variable consideration for the ongoing platform service, which is a common reading when access is a series of substantially identical monthly services.
Step 3: the transaction price doesn't know about usage yet
The transaction price is what you expect to be entitled to. The fixed part is €30,000. The API fee is variable consideration, and IFRS 15 lets you include it only to the extent that it's highly probable a significant reversal of recognised revenue won't occur later.
For fees measured and billed monthly in arrears there's a practical route. If a variable payment relates solely to one month's service, you allocate it entirely to that month instead of spreading it across all obligations, provided the result is consistent with the standard's allocation objective. In the example, January usage is January revenue once it has been measured.
Minimum commitments, expiring credits and tiers that apply retrospectively to the whole year are different. Suppose the price drops to €0.008 for every call once annual volume passes two million. January's €0.01 is then provisional, and you need an estimate of annual volume with a constraint on it. Model that tier as an ordinary monthly tier in your pricing logic and you'll post a December revenue adjustment that nobody can explain.
Step 4: allocating €30,000 by standalone selling price
In Case A the €30,000 must be split across two obligations in proportion to their standalone selling prices. Invoice amounts don't enter into it. Say you regularly sell the licence on its own for €27,000 and a comparable migration for €9,000. The customer gets €36,000 of list value for €30,000.
| Performance obligation | Invoiced | Standalone selling price | Share | Allocated price |
|---|---|---|---|---|
| Annual licence | €24,000 | €27,000 | 75% | €22,500 |
| Data migration | €6,000 | €9,000 | 25% | €7,500 |
| Total | €30,000 | €36,000 | 100% | €30,000 |
The migration carries €7,500 of revenue although the invoice says €6,000. The licence carries €22,500, so €1,875 a month rather than €2,000. The €6,000 discount is spread proportionally because nothing suggests it belongs to one obligation only. You can allocate a discount to part of a contract when there's observable evidence that it relates to that part, and you need to document that evidence.
A standalone selling price is master data. It belongs in the product catalogue with a version, a validity period and a note on how it was derived, for example from observed standalone sales or list price less typical discounts. If you change it in March, January's allocations must not move. Our post on product catalogue versioning covers how to keep that history.
Step 5: what the ledger shows at the end of January
The licence is satisfied over time, straight-line across twelve months. We assume the migration is completed in January. Metering recorded 180,000 API calls in January, so €1,800, invoiced in early February. The €30,000 invoice is due immediately.
| End of January | Case A: migration distinct | Case B: migration not distinct |
|---|---|---|
| Licence revenue | €1,875 | €2,500 |
| Migration revenue | €7,500 | included in licence |
| Usage revenue | €1,800 | €1,800 |
| Total January revenue | €11,175 | €4,300 |
| Contract liability | €20,625 | €27,500 |
| Unbilled usage receivable | €1,800 | €1,800 |
Same contract, same invoice, and a €6,875 difference in January revenue. That number hangs on one catalogue decision made in step 2.
VAT runs on its own rules, such as when the supply takes place and how advance payments are treated, not on the revenue schedule. The €30,000 invoice needs every mandatory field your VAT law requires however you spread the revenue. Tax and revenue recognition are two rulebooks that share keys: customer, contract and service period. For getting the resulting entries into the general ledger, see our piece on DATEV exports from billing.
Month seven: upgrade as a new contract or as a modification
In July the customer adds a module. How it hits the schedule depends on two questions: is the module distinct, and is it priced at its standalone selling price?
- Both yes: the module is a separate contract with its own schedule. January's contract is untouched.
- Distinct, but at a special discount: you treat it as if the old contract ended and a new one began. The licence consideration not yet recognised (€11,250 in Case A) plus the module price is reallocated across the remaining obligations prospectively.
- Not distinct, for example an extension that changes the existing service: you adjust with a cumulative catch-up at the modification date.
Proration on the invoice answers none of this. It works out what the customer pays for the remaining six months. The revenue side also needs the modification's classification. Store it on the change event, or someone will reconstruct it from email threads at close.
The data billing has to hand to revenue
A revenue module is only as good as the events it receives. For the example contract that means at least:
- Contract with version, term and links to related documents
- Contract line pointing to a performance obligation, not just a product
- Standalone selling price per obligation, versioned with a validity period
- Satisfaction method per obligation: over time, at a point in time, or by usage
- Usage events with customer, meter, service period, quantity, source and idempotency key
- Modification events with date and classification: separate contract, prospective or catch-up
Late usage events are a routine way for the subledger and the general ledger to drift apart. If an event for January arrives on 3 February after January is closed, you need a fixed rule: post it in the open period with a reference to the service period, or reopen January. Duplicate deliveries must never count twice. The IETF Idempotency-Key header draft describes the pattern, and our post on idempotent usage event processing shows it applied to billing.
Five questions finance answers before automating
Before schedules are generated automatically, get these answers in writing:
- Which catalogue products are distinct performance obligations, and why? Start with every set-up, onboarding and implementation fee.
- Where do standalone selling prices come from, and who may change them?
- Which price components act retrospectively (annual tiers, minimum commitments, expiring credits) and therefore need an estimate?
- How is each type of contract change classified, and where is that stored?
- Up to what cut-off are late usage events still assigned to their service month?
Then run one contract like the one above end to end: invoice, schedule, ledger posting, July upgrade. Only when January matches your hand calculation is it worth rolling out to more contract patterns.
Kontier links contract and usage events to metering, invoicing and revenue schedules; the usage-based billing page lists what it covers.
Not tax or legal advice. This post describes the law and common practice in general terms. For your own case, ask your tax adviser. As of: