StabisoDocs

Sales and customers

Subscriptions

A subscription sells recurring products to a customer for a committed term (1 to 60 months), billed monthly, quarterly or yearly, in advance or in arrears. A second person approves its terms; the approval activates the term's revenue contract, and the billing run invoices each period against that contract, so what is billed goes to the contract liability and the period-end recognition run books the revenue month by month. The design is ADR-0036 section 4; this guide is slice 4 as built, with ending a term early and renewals (ADR-0047). Upsells, downsells and price changes of an active subscription are still to come. The controls are in the control matrix (section "Subscriptions", SB1 to SB5).

Everything is a REST operation first (/v1, tag "subscriptions" in the generated reference); the MCP tool list_subscriptions reads the same operations.

The subscription

The New subscription form says under each field what goes in it and offers the usual values with one click: a start of today or the 1st of next month, a term of 12, 24 or 36 months, a renewal notice of 30, 60 or 90 days and an uplift of 3 or 5 %.

POST /v1/subscriptions                            {entity, party, title, start_date, term_months, billing_frequency?, billing_timing?, auto_renew?, renewal_notice_days?, renewal_uplift_percent?, payment_terms_days?, auto_submit?, opportunity?, lines}
GET  /v1/subscriptions                            ?entity&status&party_id
GET  /v1/subscriptions/{subscription_id}
POST /v1/subscriptions/{subscription_id}/cancel   {reason}

A subscription is created as a draft by anyone who may draft, an agent too, and numbered SUB-000001 per entity. The term is a whole number of billing periods (a quarterly subscription runs 3, 6, 9 ... months) and ends the day before its months are up: 12 months from 16 January end on 15 January. A subscription starts in an open period: one back-dated into a closed period is refused when it is created and when its terms are approved. Each line names a product that is recurring, active and not goods, and has a standalone selling price on the start day; quantities and prices have at most six decimals, percentages at most four; the line's price per month or year is the product's list price on that day unless the line gives its own unit_price, less its discount_percent. The description and revenue account default to the product's. The subscription bills in a currency: currency as given, else the won deal's currency, else the customer's, else the entity's functional currency (ADR-0050). Its prices, invoices, credit notes, renewals and revenue contracts are all in that currency, and each product needs a list price (or the line its own unit_price) and an SSP in it on the start day: a price is never converted. A product priced only in other currencies is refused with subscription_currency_unpriced, which names the currencies it has prices in; a missing SSP with subscription_ssp_missing. A currency the ECB rates do not cover is refused with fx_rate_missing. The approval policy compares the term's amount in the functional currency (at the rate of the start day, or of the day it was drafted when it starts later). Creating it builds its first invoice without keeping it, so a customer's VAT treatment or an account that cannot work is found now. A draft's terms are not edited: cancel it (a reason is kept) and create a new one.

What a term costs, term_amount, is each line's monthly amount (quantity times the price per month, less the discount, kept exact) times the term's months, rounded once to the currency.

Approval and the term's revenue contract

POST /v1/subscriptions/{subscription_id}/activate
POST /v1/approvals/{approval_id}/approve          {comment?}

activate asks for the terms to be approved. A second person always decides: never the person who drafted the subscription or asked, never an agent (the policy action approve_subscription), and never the requester alone even where an organization's policy allows the action; a policy that denies it refuses the request. The approval is bound to the digest of the terms. The database holds the same rule: it activates a subscription only from pending_approval, approved by a person who did not create it, through an approved request someone else made, with the term's own contract; the lines and terms of a subscription never change. Approving, in one transaction:

  1. creates the term's revenue contract (RC-2026-000001): the term's dates, the transaction price the term's amount, and one over-time obligation per line, recognised by the monthly method, with the line's product and quantity, so its SSP is the product's over the term and the price is allocated by relative SSP. Billing in arrears makes the right to consideration unconditional (only time stands before each invoice), billing in advance conditional;
  2. activates that contract, which writes its schedule;
  3. makes the subscription active, with the contract and the first period to bill (next_bill).

A rejection returns the subscription to draft. When every line is priced at its product's SSP the allocation equals the line prices and each month's revenue is what is billed for it. A line sold below its SSP moves revenue between the obligations, as IFRS 15.74 requires: 10 seats at CHF 50.00 a month less 10 % and an add-on at CHF 20.00 (SSP 25.00) bill CHF 450.00 and 20.00 a month, while the contract allocates CHF 5,371.43 and 268.57 over the year. The billing cap is the contract's, so each invoice may bill its list prices.

Billing

POST /v1/subscriptions/run                        {through, entity?, subscription?}
GET  /v1/subscriptions/{subscription_id}/invoices

The run invoices every billing period of an active subscription whose invoice date is on or before through (at most a day after the server's date): in advance on the period's first day, in arrears on the day after its last. When that day is in a closed period, the invoice is dated the first day of the next open period (its lines still name the service period), so closing a period never stops billing. Each invoice has a line per subscription line for the period's part of the line's term amount (the difference of two cumulative amounts, so the periods of a term add up to it exactly), shown as the line's quantity at the period's unit price, discount included (25 seats x 38.00; 1 x the amount when no unit price of six places multiplies to it exactly), naming its obligation: Dr receivables / Cr contract liability / Cr VAT. The product gives the VAT treatment. Without auto_submit the invoice is a draft for a person to submit; with it, the system submits it through the approval policy, the open period and the numbering. A run's draft bills what was approved: its customer, currency, cash discount, products, quantities, prices, obligations, accounts and what decides its VAT (supply type, rate type, tax category, VAT scope) cannot be changed (its dates and notes can). To bill otherwise, void the draft: the next run makes that period again. The invoices list shows what the run did (status) and each invoice's own status now (document_status).

The run is idempotent: one invoice per subscription and period, enforced by the database, and a subscription is locked while it is billed. A period that cannot be made (an inactive customer, the contract's billing cap after an invoice billed the obligation by hand, terms that no longer match the approved digest) is recorded as failed with its error and stops that subscription at that period, never the others in the run; the next run tries it again. The run is a person's request: an agent is refused, since with auto_submit it posts invoices. At most twelve periods of one subscription are billed in a run (more_due says to run again). A fully billed subscription stays active until its term ends; the first run after that renews it (see Renewals) or, when nothing renews it, marks it ended once every invoice it made is posted: a draft may still be voided, and the next run then makes that period again. A period whose invoice date is past through is left for a later run before anything else is looked up, so a next period in a fiscal year not opened yet never stops a run; one a run does reach there is made as a draft (posted once the year is opened) or, with auto_submit, fails that subscription only. A late invoice goes to the next open regular period, never a one-day adjustment period.

The close check subscriptions_billed (a warning) names subscriptions with a period due through the period's end and not billed, and invoices a run made through it that are not posted (a draft, waiting for approval, rejected or voided). It does not block the close: a late period is invoiced in the next open period. The period-end recognition run recognises the term's revenue month by month and presents what was recognised and not billed (in arrears) as an unbilled receivable; the run of the term's last month marks its contract completed once every month is recognised. The subscription shows ended from its own billing run, without waiting for the contract.

Ending a term early

POST /v1/subscriptions/{subscription_id}/amendments/preview   {kind: "cancel", end_date, proration?, reason}
POST /v1/subscriptions/{subscription_id}/amendments           {kind: "cancel", end_date, proration?, reason}
GET  /v1/subscriptions/{subscription_id}/amendments

An active subscription is not cancelled: its current term is ended early by an amendment that a second person approves, as its terms were (approve_subscription, never the person who asked, never an agent). end_date is the last day of service, within the current term. proration says what happens to what was already billed past that day: prorate (the default) credits its unused part, none keeps it as a non-refundable prepayment. The preview and the request show the term's price before and after, the part earned through the last day and a credit per billed period, worked out from what is posted now; the approval is bound to those amounts, and approving refuses with terms_changed when they moved in between (reject it and ask again). An amendment is refused while an invoice of the subscription is not posted, when revenue is already recognised after the last day (an end is prospective), or while another amendment waits.

Approving, in one transaction: billing stops after the last day (the period it falls in, if not billed yet, is billed for its days: 10 seats at CHF 50.00 ended on 20 June bill round(500.00 x 20/30) = 333.33 for June); with prorate the system posts a credit note for each period billed past the last day, its lines naming the obligations (Dr contract liability / Dr VAT / Cr receivables); and the term's revenue contract is modified prospectively: its price becomes what the customer now pays for the term, its end the last day, the schedule lines not yet recognised are superseded and what is left is spread over the remaining days, recognised revenue stays. Billing and revenue count a month the same way, from the subscription's start day: a subscription from 15 February has months from the 15th to the 14th, so its schedule books 14 of the 28 days from 15 February (250.00 of 500.00) for February and 14/28 + 17/31 of a month for March, and ended on 31 May it has earned 3 months and 17/31 of the fourth, exactly what its schedule says and what is left billed after the credit. With none, the part of the prepayment for service not given is recognised on the last day. The subscription shows ends_on, and the first run after that day marks it ended. Ending on the term's last day stops a renewal without changing anything else. On screen: End early in a subscription's dialog.

Changing the plan within a term

POST /v1/subscriptions/{subscription_id}/amendments/preview   {kind: "change", effective_date, lines, reason}
POST /v1/subscriptions/{subscription_id}/amendments           {kind: "change", effective_date, lines, reason}

An upgrade or a downgrade (more or fewer seats, another product, price or discount) is a change amendment a second person approves, as every amendment (ADR-0059). lines are the subscription's lines from effective_date on, the ones that stay named again (a price left out is the list price that day); effective_date is after the first day of the lines in force and at the latest the term's last day. The term, the billing frequency and the timing stay.

Approving, in one transaction, ends the current lines the day before exactly as an early end with prorate does (what was billed past that day is credited, a credit note per invoice, and their revenue contract is modified to end that day) and starts the new lines that day with a revenue contract of their own for the rest of the term, activated in the approver's name. The first period of the new lines is cut at their first day, so it charges only the rest of that period; when its invoice date has come it is billed at once. Example: 10 seats at CHF 50.00 a month, billed in advance from January; on 16 March 12 seats from that day. March's invoice is credited 258.06 (16 of 31 days at 500.00), the new lines invoice 309.68 for 16 to 31 March (600.00 x 16/31) and 600.00 a month from April. The old contract ends on 15 March at 1,241.94, the new one runs from 16 March at 5,709.68, and March recognises 241.94 + 309.68. A change from the first day of the next period credits and charges nothing in between.

In arrears, or when an invoice of the current lines is not posted yet, the subscription keeps changes_on (the new lines' first day) until the current lines are billed and posted through the day before; the billing run then moves to the new lines. While changes_on is set no other amendment is asked. A subscription in another currency changes in that currency (its contracts too). On screen: Change plan in a subscription's dialog: from today, the next period or another day, the new lines, and the preview of the credit, the first charge and the new lines' price to the term's end.

Renewals

POST /v1/subscriptions/{subscription_id}/amendments   {kind: "renew", reason}

A renewal starts the next term the day after the current one ends: as long as the term, its months counted from the subscription's start day (a one-month term from 31 January renews on 28 February, then 31 March, never drifting to the 28th), billed at the prices in force raised by renewal_uplift_percent (each price rounded to the cent: 50.00 + 3 % = 51.50, then 53.05), with its own revenue contract: a renewal is a new contract, never a modification. With an uplift, each line is closed on the term's last day and a line at the new price opens the next day.

  • With auto_renew, the approved terms are the authority: the first billing run after the term's last day, once every period of the term is billed, starts the next term (its contract activated by the system) and bills its due periods.
  • Without, a person asks for the renewal (Renew in the subscription's dialog; the preview shows the next term's days and price) and a second person approves it, as an amendment. Approved before the term ends, the run starts the next term after its last day; approved after, it starts at once. The contract is activated in the approver's name. Without a renewal the run ends the subscription; while a renewal request waits, it does not. A renewal that was due is not lost when the run ended the term first: a subscription ended with its term (not ended early) still shows its renewal due, Renew stays in its dialog, and the approval makes it active again and starts the next term at once, the day after the old one ended (its periods are billed by the next run).

renewal_status says what happens next: auto, approved (with renews_on), requested, due (from renewal_notice_days before the term's last day, renewal_due_on, while nothing renews it; the list marks it renewal due), upcoming, or ends for a term ended early. term_no counts the terms. The database starts a term only with its subscription_renewal row: the next term counted from the start day, of an active subscription not ended early, with an active contract for exactly its days, under auto_renew or the applied renewal of the term before.

Renewal deals and recurring revenue

A subscription whose renewal is due gets a renewal deal in the pipeline, won or lost with the renewal, and its MRR counts in the recurring revenue report: see recurring revenue.

Stabiso, the Enterprise System of Record · generated from the code and its guides · release 20b7dd5b0c4d