The idea
A single-tenant app that pulls login and activity history out of every SaaS admin API your company uses, puts it next to the seat count on the invoice, and produces one list: who is paying for what and hasn't signed in. It also knows each contract's renewal date, so the list arrives while cancelling is still possible instead of eleven months too late.
Why build this
Every company over about thirty people is paying for seats belonging to contractors who finished in March, people who moved teams, and the two people who tried the tool and went back to the spreadsheet. Finance sees a line item for 120 seats. IT knows how many accounts exist. Nobody knows how many are actually used, because that answer lives in six different admin consoles and none of them talk to billing.
The existing answer is a SaaS management platform that wants a per-employee price and read access to your identity provider. For a company that already self-hosts, that's both an expense and a data-sharing decision to justify. The admin APIs are all public and all boring: Google Workspace, Okta, Slack, GitHub, Atlassian, and Zoom will each tell you last-login per user if you ask. Nobody has bothered to glue them to an invoice.
Timing is good because seat-based pricing is being replaced by usage-based pricing in a lot of places, and the companies still selling seats are enforcing true-ups harder. Knowing your real utilisation is now leverage in a renewal conversation, not just a tidy-up.
Stack sketch
- Python 3.12 + FastAPI for the app, APScheduler for nightly collector runs
- Collectors as one module per vendor: Google Workspace Admin SDK Reports API (
activities.listwithapplicationName=login), Okta System Log API, Slackadmin.users.listplusteam.billableInfo, GitHubGET /orgs/{org}/membersplus the org audit log, Atlassian/rest/api/3/users, Zoom/users(last_login_time) - Postgres: an
identitiestable keyed on email, aseat_eventsappend-only table, acontractstable holding seat count, unit price and renewal date - Contract side ingested as CSV or invoice PDF, parsed with
pandasandpdfplumber; no vendor billing API is worth the integration at v1 - SvelteKit + Tailwind frontend, server-rendered tables, no SPA state to debug
- OIDC login via
authlibagainst the customer's own IdP aiosmtplibfor the renewal digest; ships as Docker Compose with one app container and Postgres
Scope for v1
In: - Three connectors: Google Workspace, Slack, GitHub - Email-based identity matching, with a manual alias table for the cases it gets wrong - CSV contract import - One report: per app, seats billed vs. seats with a login in the last 30/60/90 days, with an estimated monthly saving - A weekly email digest and a 30-days-before-renewal reminder
Out: any write path or auto-deprovisioning, apps without an admin API, cost forecasting, multi-tenancy, anything resembling a chart.
Where it could go
The obvious next step is the write path — SCIM deprovisioning so the report has a button, with an approval step so one bad identity match doesn't lock someone out of their email. That turns it from a report into a workflow, which is where people start paying.
After that, tier detection is the bigger prize. Most seat waste isn't unused accounts, it's 80 people on the Business plan who only ever use the features in Pro. The same activity feeds can answer that if you model per-feature events rather than just logins. A third path is department chargeback: once identities are mapped to an HR system, you can hand each team their own SaaS bill, which tends to reduce seat count without anyone having to enforce anything.
Watch out for
A login is not usage — some IdP logs record silent SSO session refreshes as logins, which will make dormant accounts look active unless you filter on interactive events. The other trap is retention: Slack and GitHub audit logs only go back a fixed window, so the tool has to start collecting months before it can say anything useful, and you need to be honest about that during the first weeks of a trial.