Billing forensics, packaged as fixed-scope engagements that fit around a full-time role. Starting prices shown — add-ons scale with what the project actually needs.
A part-time analyst on call, not a monthly report. Up to 5 hrs/week async support and priority turnaround — capped at 2 clients so response time never slips.
metrics = ["revenue", "ad_spend", "churn"] pulse = {m: flag(df, m) for m in metrics} send_digest(pulse, channel="#pulse")
Hand over a billing export, get back a ranked list of overcharges, duplicates, and missed credits — dollar amounts attached, summarized for whoever signs the check.
baseline = revenue.rolling(6).mean().shift(1) z = (revenue - baseline) / spread.clip(lower=baseline*0.03) flagged = invoices[z.abs() >= 2.5]
The same detection logic, run on a fixed monthly schedule. One short report flags anything new before it compounds into next quarter's surprise.
SELECT account_name, amount_due - COALESCE(paid,0) AS net_balance FROM invoices LEFT JOIN payments USING(invoice_id) WHERE net_balance > 0.01 ORDER BY net_balance DESC;
Ad spend, MRR, churn, subscriptions — the same baseline-deviation method, applied to any monthly metric that's supposed to behave predictably and didn't.
def flag(df, metric, w=6, z=2.5): base = df[metric].rolling(w).mean().shift(1) std = df[metric].rolling(w).std().shift(1) return df[((df[metric]-base)/std).abs() >= z]
A query set or multi-tab Excel build that replaces the manual reconciliation someone is currently doing by hand — built once, reused every cycle.
WITH aging AS (SELECT invoice_id, current_date - due_date AS days_late FROM invoices) SELECT SUM(CASE WHEN days_late>90 THEN 1 ELSE 0 END) AS d90 FROM aging;