Trial SKUs that auto convert

07 Sept 2026

Trial SKUs that quietly become paid subscriptions

Nobody signs a contract. Someone in marketing wanted Power BI for a week, a project manager wanted to test Project Plan 3, a partner suggested trying Entra ID P2 "just to see". Thirty days later Microsoft does exactly what it said it would do on the sign-up page, and a line appears on an invoice that nobody in IT recognises.

This is not a billing bug. It is documented behaviour working as designed, in a place your monitoring almost certainly doesn't look. Six questions, in the order admins actually ask them.

30
days of free trial
25
free seats included
Annual
default term it converts to
0
trial fields on subscribedSku

How does a trial become a paid subscription with nobody approving it?

Because that is the deal. Microsoft's page on what happens when a subscription ends puts it in one sentence: "At the end of your trial period, we automatically start billing you for your subscription." The approval happened at sign-up, by whoever clicked.

The detail that turns a small surprise into a big one is the term. Adding a trial to a tenant renews "to an annual term subscription by default" unless recurring billing is turned off first. So the mistake isn't a month of Power BI you didn't need — it is twelve, and by the time it appears on the invoice you are inside the committed term rather than in front of it. That is the same one-way door the NCE annual commitment closes, reached by accident instead of by decision.

Two more numbers from the same sign-up flow are worth knowing. A trial added to an existing tenant comes with 25 free licences for the trial period — and the flow separately asks for "the number of licenses that you want to buy when the trial ends". Those are two different quantities, decided in the same three minutes, by someone who was thinking about the first one.

ONE TRIAL SKU: WHAT THE TWO PROPERTIES SAY, AND WHERE THE DOORS ARE Free trial isTrial: true · 25 seats status: Enabled Paid annual term isTrial: false · the quantity chosen at sign-up status: Enabled — nothing in the tenant changed shape automatic day 0 — sign-up day 30 — conversion +12 months nextLifecycleDateTime the same field, now pointing a year away Door 1: recurring billing off open the whole time, costs nothing Committed term — Door 2 is the renewal date cancellation window aside, this is where you now live The conversion changes one boolean. It does not change the status, the seat count you see, or anything that alerts.

Who started it, and can I see their name?

Graph names them. Each companySubscription carries ownerId — documented as "the object ID of the account admin" — plus ownerType ("User") and createdDateTime. Resolve that GUID against the directory and the March click has a name on it.

The admin center shows the same thing in prose: Billing → Your products → Self-service trials lists the product, the purchaser name, the expiration date, the purchase price and the assigned users. It exists, it's one tab, and almost nobody opens it monthly — which is the entire reason this article has an audience.

Why doesn't /subscribedSkus tell me any of this?

Because it was never about subscriptions. The subscribedSku resource is a seat-counting object: consumedUnits, prepaidUnits, capabilityStatus, servicePlans. Read the property list end to end and there is no trial flag, no renewal date, no expiry, no purchaser. A trial SKU and a three-year enterprise commitment are the same shape of row.

That matters because /subscribedSkus is what almost every licence script and dashboard is built on, including the ones that find licence waste. They are answering "how many seats are assigned", correctly, and staying silent about "which of these bills me next month" because the object they read cannot express it.

The one call

GET /directory/subscriptions returns the same tenant as a list of commercial subscriptions instead of seat pools — with isTrial, nextLifecycleDateTime, status, totalLicenses and ownerId on every row. Least privileged permission: Organization.Read.All. It is one unpaginated GET, and it is the difference between a licence inventory and a renewal calendar.

What is nextLifecycleDateTime actually counting down to?

Not "renewal", despite how everyone reads it. The documented meaning is narrower and more useful: the date the subscription "will move to the next state (as defined by the status property) if not renewed by the tenant". Same field, different destination depending on where the row is standing.

Row looks like What that date is
isTrial: true, status: Enabled The day it starts costing money. This is the only row type where the date is a deadline for you, not a diary note.
isTrial: false, status: Enabled The renewal date — and the one window where the seat count and the term are yours to change.
status: Warning Past the end date, still fully working for users. The grace period, quiet by design.
status: Suspended Users have lost the apps; admins can still get in and take the data out. A date here is a countdown to deletion.
status: LockedOut / Deleted Terminal. Microsoft is explicit that buying the same subscription again does not bring the data back.

Behind those statuses is a fixed clock: for most offers a subscription that ends sits Expired for 30 days — users fully working, nothing visibly wrong — then Disabled for 90, where users lose access and only admins can still reach the data, and then it is deleted. Three months of silence, then a cliff.

Can I just block self-service trials?

Partly, and the shape of "partly" is the point. Microsoft states it plainly: self-service purchases and trials "can't be completely turned off at the tenant level with a single command". The AllowSelfServicePurchase policy is per-product, so turning it off tenant-wide means turning off every product individually — and by default all new products are set to allow it. Microsoft ships a product, it is on.

Two more edges worth budgeting for: changes can take up to 72 hours to apply, and the trials themselves are not uniform. Some self-service trials require a payment method at sign-up and automatically convert; others require no payment method and don't auto-renew at all — but those are "only available to select customers with an existing subscription agreement". You cannot tell which kind you have by looking at the product name.

It already converted. What are my options?

Fewer than you'd like, and one of them is genuinely surprising: for a subscription a user bought or trialled themselves, you can't assign or unassign its licences at all. It isn't yours. The admin center gives you one button — Take control of this subscription — and from there two routes: move the users onto a subscription you already own (which cancels the original automatically), or cancel it outright and strip the licences.

Both are fine. Both are also a conversation with a colleague who thinks they bought a working tool, which is why the cheap version of this whole problem is a list you look at before day 30 rather than after.

The thing to actually build

Not a report. A filter: every subscription where isTrial is true, sorted by nextLifecycleDateTime, checked more often than your invoice arrives. It is one Graph call, one boolean and one date — and the reason it doesn't exist in most tenants is that the object carrying those three things is not the object anybody's licence tooling reads.

GraphPaaS collects /directory/subscriptions per tenant on a schedule and keeps the history, so a trial that appeared last Tuesday is a row with a date on it and a name attached, weeks before it becomes a line on an invoice.

Sources
GraphPaaS

Every trial in the tenant, with the date it stops being free — before the invoice tells you.

See your subscriptions →

Newsletter

Get the next article by email

Practical M365 & Azure cost pieces like this one. No spam, unsubscribe anytime.