vertiq
Software and subscriptions

Software and subscriptions

Predict cancellations and downgrades, and estimate renewal value from product usage and billing events.

Data mapping

Entity
account
Group
plan
Profile
generic; configure time windows with verticals.register
SOURCE COLUMNSVERTIQ DATA CONTRACTAccount IDEvent TimeEventMRR ChangePlanSeatsRegionEntity · identifierEvent · timestampEvent · typeEvent · valueEntity · groupEvent · attributes%Y-%m-%dT%H:%M:%S
Vertiq LM can propose this mapping from the header and sample rows. Column names, value types and the date format are validated against the data before use.

Supported analyses

Reference implementation

from datetime import datetime, timedelta
from vertiq import plugins, rules
from vertiq.mapping import Mapping, apply, repair
from vertiq.tasks import predict_event, predict_value

# rows: the source export as a list of dicts, e.g. list(csv.DictReader(open("export.csv")))
mapping = Mapping.parse({"entity": "Account ID", "time": "Event Time", "type": "Event", "value": "MRR Change", "group": "Plan", "attrs": ["Seats", "Region"], "date_format": "%Y-%m-%dT%H:%M:%S"})
m, notes = repair(mapping, rows)      # validates column names, value types and date format against the rows
ds, problems = apply(m, rows)         # rows that fail to load are reported, not imputed

@plugins.feature("saas")
def usage_drop(entity, before, cut):   # receives only events recorded before the cutoff
    now = sum(1 for e in before if e.type == "login" and e.at >= cut - timedelta(days=30))
    prev = sum(1 for e in before if e.type == "login"
               and cut - timedelta(days=60) <= e.at < cut - timedelta(days=30))
    return {"login_ratio": (now + 1) / (prev + 1)}

task = predict_event(ds, target="cancel", window_days=30, pack="saas")
print(task.status, task.report())     # "trained" only if the model outperformed the baseline on held-out entities
if task.status == "trained":
    print(task.score("acct_7f2"))  # probability with contributing factors

size = predict_value(ds, target="renewal", window_days=365, pack="saas")
print(size.status, size.report())

flags = rules.run(ds, [
    rules.repeat(7, type="payment_failed"),   # a second failed payment within seven days
])
print(flags["summary"])

This code is executed by the test suite (tests/test_guides.py) against generated records with these column names.

Recommended plugin

usage_drop: Declining product usage is an early indicator of cancellation.

Validation rules

  • rules.repeat(7, type="payment_failed"): a second failed payment within seven days

Related modules

  • insights: statistically tested patterns, such as onboarding actions associated with retention
  • survival: probability of renewal or cancellation given time since the last activity
  • design: the size of control group needed to measure an onboarding change

Implementation notes

  • Aggregate high-frequency usage events to daily counts before mapping.

Validation

  • Every deployment: the evaluation gate measures each model on the organisation's own held-out records before promotion.
← Energy and utilitiesWholesale and distribution →