Licensing rules (add-on)
Which products issue a key, and on what terms.
Which products issue a key, and on what terms. A variant rule wins over its product's rule. See Licenses.
List licensing rules
/api/v1/kahunacart/licenses/products
Every licensing rule in the store with the catalog beside it, plus the rule kinds, the subscription endings, the placeholder legend the delivery copy is written in and the store's default key layout with a sample key. A rule decides which products earn keys, how many, and on what terms. Rules resolve variant over product: a rule with no variant covers every variant of its product, and a rule naming a variant replaces it for that variant only. Call this before writing a rule, to see what is already there and to get the product and variant ids.
What an order is owed in keys
/api/v1/kahunacart/licenses/issuance/{orderId}
Whether one order's lines earn license keys, how many it has been given already, and which event the store mints them on — paid waits for the money to land, completed issues the moment the order is placed. Use it to tell an order that sells nothing licensed from one whose keys have not been minted yet, which is the difference an empty key list cannot show. The count is the issuer's own plan, so a rule naming one variant, a disabled rule and the quantity models are all accounted for. Renewal lines are not counted: a renewal adds time to a key the customer already holds and mints nothing. addons lists every product the order put on an existing key, each with the key it landed on, including the extra products a bundle variant grants. An unknown order answers 404.
Parameters
| Name | Type | Description |
|---|---|---|
| orderId required | integer | The order to ask about |
Write a product's licensing rule
/api/v1/kahunacart/licenses/products/{productId}
Create or replace the product-wide licensing rule, which governs every variant that has no rule of its own. Addressed by the product rather than by a rule id, so saving the same body twice writes the same row twice and there is no "did I already create this" question to get wrong. Only the fields sent are written, and each is judged against the rule as it will be after the save, not against this request alone. A renewal with no renews_product_id and an addon with no attaches_product_id are refused with 422, as is a rule pointing at itself, an unknown product, a bad key prefix or format, and a license file with no name or no contents. An unknown product answers 404. Changing the key layout only affects keys issued from then on.
Parameters
| Name | Type | Description |
|---|---|---|
| productId required | integer | Catalog product the rule governs |
| enabled optional | boolean | Off stops the store issuing keys for this product. Keys already sold keep working; suspend or revoke those individually |
| kind optional | string |
license mints a key; renewal buys more time on a key the customer already holds and mints nothing; addon widens a key they already hold
One of:
license, renewal, addon |
| renews_product_id optional | integer or null | Required on a renewal: the licensed product this one extends. Left null a renewal accepts any live key in the store, which is usually a mistake |
| attaches_product_id optional | integer or null | Required on an addon: the licensed product whose key this widens |
| keys_per_qty optional | integer | Keys minted per item bought. 0 mints none. Ignored on a renewal |
| seats optional | integer or null | Machines a key may run on at once. null is unlimited. Ignored on a renewal |
| seats_per_qty optional | integer | Extra seats added per item bought, on top of `seats`. Ignored on a renewal |
| term_days optional | integer or null | Days the key runs for. null is perpetual. On a renewal this is the term the money buys, added to whatever is left |
| updates_days optional | integer or null | Days of updates entitlement, separate from the term. null is forever. On a renewal this is the window the money buys |
| on_subscription_end optional | string |
What happens to a key when the subscription paying for it stops, and only ever for keys the Subscriptions add-on pays for. nothing leaves the customer the term they already paid for
One of:
nothing, suspend, revoke |
| key_prefix optional | string or null | Up to 8 letters or digits marking the keys this product issues. Ignored on a renewal |
| key_format optional | object | Layout override for this product's keys. Every field is optional and an absent one inherits the store's, so a rule can differ in one respect without restating the rest. null or an empty object means the store format. Keys: `prefix`, `blocks`, `block_length`, `alphabet`, `separator`, `template` |
| instructions optional | string | Markdown shown to the customer for this product, written in the placeholder vocabulary |
| meta optional | object | Free-form object stored on the rule. null or an empty object clears it |
| grants optional | array of integer | Only on an addon: extra product ids this add-on rule also puts on the key beside its own product, so a bundle can be sold as a variant. At most 20. Refused with 422 when an id is not a positive whole number, names no product, repeats, is also in requires, or is the rule's own product or the one it attaches to. An empty list clears them |
| requires optional | array of integer | Only on an addon: product ids the key must already cover before this add-on can be bought. A line for one of them in the same basket, or a line whose rule grants it, counts as having it. Checked when the line is added to the cart and again at checkout. At most 20. Refused with 422 on the same mistakes as grants, and when an id is also in grants. An empty list clears them |
| includes optional | array of object | Packages this licence covers from day one that are not sold as products of their own, such as bundled payment plugins, at most 100. They print in the licence's product list after the product it was sold under and every add-on bought against it. An empty list clears them. Keys: `slug`, `title` |
| files optional | array of object | License files generated for each key from these templates, at most 20. Nothing is stored on disk, so a file downloaded a year later reflects the licence as it stands then. An empty list clears them. Keys: `name`, `content_type`, `template` |
Write a variant's licensing rule
/api/v1/kahunacart/licenses/products/{productId}/{variantId}
Create or replace one variant's own licensing rule, which replaces the product-wide rule for that variant and leaves every other variant on the product's. Use it to license a "Team" variant on different terms without writing a rule for every other variant, or to sell renewal lengths as variants that differ only in price and updates_days. The body, the validation and the refusals are exactly save_product_rule's; a variant belonging to a different product answers 422.
Parameters
| Name | Type | Description |
|---|---|---|
| productId required | integer | Catalog product the variant belongs to |
| variantId required | integer | Variant the rule governs. Must belong to productId |
| enabled optional | boolean | Off stops the store issuing keys for this variant |
| kind optional | string |
renewal must name renews_product_id, addon must name attaches_product_id
One of:
license, renewal, addon |
| renews_product_id optional | integer or null | Required on a renewal: the licensed product this variant extends |
| attaches_product_id optional | integer or null | Required on an addon: the licensed product whose key this widens |
| keys_per_qty optional | integer | Keys minted per item bought. 0 mints none. Ignored on a renewal |
| seats optional | integer or null | Machines a key may run on at once. null is unlimited. Ignored on a renewal |
| seats_per_qty optional | integer | Extra seats added per item bought, on top of `seats`. Ignored on a renewal |
| term_days optional | integer or null | Days the key runs for, or the term a renewal buys. null is perpetual |
| updates_days optional | integer or null | Days of updates entitlement, separate from the term. null is forever |
| on_subscription_end optional | string |
What happens to a key when the subscription paying for it stops
One of:
nothing, suspend, revoke |
| key_prefix optional | string or null | Up to 8 letters or digits marking the keys this variant issues |
| key_format optional | object | Layout override for this variant's keys. Absent fields inherit the store's. Keys: `prefix`, `blocks`, `block_length`, `alphabet`, `separator`, `template` |
| instructions optional | string | Markdown shown to the customer, in the placeholder vocabulary |
| meta optional | object | Free-form object stored on the rule |
| grants optional | array of integer | Only on an addon: extra product ids this add-on rule also puts on the key beside its own product, so a bundle can be sold as a variant. At most 20. Refused with 422 when an id is not a positive whole number, names no product, repeats, is also in requires, or is the rule's own product or the one it attaches to. An empty list clears them |
| requires optional | array of integer | Only on an addon: product ids the key must already cover before this add-on can be bought. A line for one of them in the same basket, or a line whose rule grants it, counts as having it. Checked when the line is added to the cart and again at checkout. At most 20. Refused with 422 on the same mistakes as grants, and when an id is also in grants. An empty list clears them |
| includes optional | array of object | Packages this licence covers that are not sold as products of their own, at most 100. An empty list clears them. Keys: `slug`, `title` |
| files optional | array of object | License files generated for each key, at most 20. An empty list clears them. Keys: `name`, `content_type`, `template` |
Delete a product's licensing rule
/api/v1/kahunacart/licenses/products/{productId}
Remove the product-wide licensing rule, so the product stops earning keys unless one of its variants has a rule of its own. Keys already issued keep working, because a rule is about issuance and never about the keys already sold; suspend or revoke those individually. A product with no rule answers 404.
Parameters
| Name | Type | Description |
|---|---|---|
| productId required | integer | Catalog product whose rule is being removed |
Delete a variant's licensing rule
/api/v1/kahunacart/licenses/products/{productId}/{variantId}
Remove one variant's own licensing rule, which puts that variant back on the product-wide rule where there is one. Keys already issued keep working. A variant with no rule of its own answers 404, including one that has only been covered by the product's.
Parameters
| Name | Type | Description |
|---|---|---|
| productId required | integer | Catalog product the variant belongs to |
| variantId required | integer | Variant whose own rule is being removed |