Licenses
Goal: Sell licences to your own customers through your own Stripe account.
Under the hero, a strip says what the window is for: "Licences, their plans and prices, and coupons, sold through this workspace's own Stripe account." "No cloud connection or landing zone is needed." "Saved changes reach Stripe when the workspace is deployed; the Health tab shows each Stripe check."
This is about what your workspace sells. Buying OpenX itself is Current License.
Before you start
- The Licenses menu appears only when you hold
Licenses.Read. Without it there is no menu. - Changing anything needs
Licenses.Manageas well. With onlyLicenses.Readthe window says: "You can view these licences. Changing them needs the Licenses.Manage right." - A workspace's owners hold all three Licenses rights with no access card. Anyone else needs them on an access configuration; no configuration grants them by default.
The tabs
| Tab | What it holds |
|---|---|
| Overview | Counts of licences, plans, prices and coupons |
| Licences and plans | New licence, Edit licence, Add plan, Edit plan, Retire plan, Add price, Edit price, Retire price |
| Coupons | New coupon per licence, and the coupons |
| Subscribers | Who holds which plan, read from Stripe; for holders of Licenses.Manage. Payment details are never shown |
| Stripe connection | Whether each Stripe key is set, the write-only keys form and the checkout and portal URLs |
| Health | Stripe connection health: each licence's state and the checks behind it |
| Stats | The main Stripe figures for each licence, for holders of Licenses.Stats.Read |
| Events | "Stripe events received": each licence's recent events (type and time only) and its verified and refused counts for the last 24 hours, for holders of Licenses.Read |
Those are the window's eight tabs, in order.
Above the tabs, the window follows a running Deploy live, and shows what the next Deploy would create, turn back on and deactivate in Stripe, read from Stripe now, with Refresh.
Licences, plans and prices
| Form | Fields |
|---|---|
| A licence | Lookup (new only; each plan's Stripe product is named from it, so keep it short), Name, Description, Enabled |
| A plan | Lookup (new only), Name, Description, Features (one per line), Priority (orders the plans, lowest first), Trial days |
| A price | Lookup (new only), Name, Amount (whole currency units), Currency, Interval (day, week, month or year), Discount |
A changed amount, currency or interval becomes a new Stripe price on the next Deploy, and the old one is deactivated; subscribers on the old price keep it. A plan's only price cannot be retired on its own. Retiring a whole licence is not available yet.
Coupons
A coupon's Promotion code is what buyers type at checkout. It has an optional Name, a Discount (a percent, or an amount in cents with a currency) and a Duration (forever, once, or repeating for a number of Months). "A coupon's terms cannot change once it is saved. To offer different terms, create a new coupon."
With Licenses.Manage each coupon has Remove coupon. It asks first: "new customers can no longer use it, and
its promotion codes are turned off. Discounts already applied keep applying. This happens at the next Deploy.
Saving alone changes nothing in Stripe." Remove this coupon saves the removal; Keep it cancels.
Stripe connection
The keys form takes the Secret key, Webhook signing secret and Publishable key. They are write-only: a blank field keeps the stored key, and "Keys saved. They are stored in the vault and are never shown again." The Checkout success URL, Checkout cancel URL and Portal return URL are where Stripe sends a buyer; "URLs saved. Checkout and the customer portal use them at once."
Save and Deploy
NOTE
Every form here saves to the workspace: "Saved. Stripe changes on the next Deploy." Nothing reaches Stripe until someone presses Deploy.
Deploy then creates each plan's product, creates and deactivates prices (Stripe prices are never deleted), and creates coupons and their promotion codes. A removed coupon is expired at Deploy and its promotion codes are turned off. A retired plan is applied at Deploy too: its prices are deactivated and its product archived. The session URLs are the exception; they are used at once.
Rights
| Right | Lets you |
|---|---|
Licenses.Read | See the menu and the window |
Licenses.Manage | Change licences, plans, prices, coupons and Stripe keys; see subscribers; retire a plan at Deploy |
Licenses.Stats.Read | See the Stats tab |
A save, an accept or a Deploy that changes licences without Licenses.Manage is refused.
Azi and agents
Azi and agents can propose licences, plans, prices and coupons, but never the Stripe keys. Any workspace member
can accept a proposal; some changes (access, licences, connected-app requests) need a management right - a
licence change needs Licenses.Manage.
Messages you may see
| Code | Message |
|---|---|
ACCESS_RIGHT_REQUIRED | "You do not hold the access right Licenses.Manage in this workspace, which is needed to change this workspace's licences, plans, prices, coupons or Stripe keys." |
LICENSE_PRICE_NOT_UNIQUE | Two prices in a plan have the same amount, currency and interval |
LICENSE_PRICE_INTERVAL_INVALID | "A price needs an interval Stripe recurs on: day, week, month or year." |
LICENSE_COUPON_LOOKUP_NOT_UNIQUE | Two coupons differ only in case; promotion codes are unique regardless of case |
LICENSE_COUPON_INVALID | The coupon's discount or duration is not valid, and the field is named |
LICENSE_SESSION_URL_NOT_HTTPS | A checkout or portal URL must be a full https address |
LICENSE_SECRET_IN_PROPOSAL | A proposal named a Stripe key. A person enters the keys here |
PLAN_UNAVAILABLE | What the next Deploy changes in Stripe could not be read just now - this is not "nothing to change" |
SUBSCRIBERS_UNAVAILABLE | Who holds which plan could not be read just now - this is not "nobody" |
Selling from your own app, and reading from an AI
- Your own app shows these plans, sells a licence to a signed-in user and checks what they hold through the Licenses API.
- Stream the Stripe events your licences receive into a data connection with the Stripe Events node.
- An AI connected over MCP reads the catalogue, health, stats, events and subscribers with
call_api(Licenses reads), and gets each licence's health fromget_stats. Try: "How are our licences doing?" The agent callsget_stats, thenGET /licenses/healthorGET /licenses/statsas the answer needs, and each read needs its own right from the table above.
Next steps
- Publish your changes -> Deploy
- Buying OpenX itself -> Current License