license_manager 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +152 -0
- data/README.md +3 -3
- data/docs/BillingPortalSession.md +18 -0
- data/docs/CancelLicense.md +22 -0
- data/docs/CancellationReason.md +15 -0
- data/docs/CancellationStats.md +30 -0
- data/docs/CancellationStatsByReasonInner.md +20 -0
- data/docs/ConnectStripe.md +1 -1
- data/docs/CreateBillingPortalSession.md +18 -0
- data/docs/CreateIntegrationMapping.md +1 -1
- data/docs/CreateLicense.md +2 -0
- data/docs/CreatePolicy.md +3 -1
- data/docs/CreateProductWithPolicy.md +1 -1
- data/docs/CreateToken.md +1 -1
- data/docs/EventActorOneOf.md +1 -1
- data/docs/Integration.md +11 -1
- data/docs/IntegrationMapping.md +2 -0
- data/docs/IntegrationMappingRecurring.md +20 -0
- data/docs/IntegrationsApi.md +74 -0
- data/docs/License.md +12 -0
- data/docs/LicenseSubscription.md +34 -0
- data/docs/LicensesApi.md +80 -3
- data/docs/Machine.md +3 -1
- data/docs/MachinesApi.md +1 -1
- data/docs/Mrr.md +26 -0
- data/docs/MrrByIntervalInner.md +24 -0
- data/docs/MrrByPolicyInner.md +22 -0
- data/docs/Policy.md +2 -0
- data/docs/PolicySettings.md +3 -1
- data/docs/PortalApi.md +80 -1
- data/docs/PortalLink.md +2 -2
- data/docs/Product.md +2 -0
- data/docs/ProductStats.md +8 -4
- data/docs/ProductsApi.md +2 -2
- data/docs/Revenue.md +10 -2
- data/docs/StripeIntegration.md +1 -1
- data/docs/StripePermission.md +5 -1
- data/docs/StripePrice.md +2 -0
- data/docs/StripePriceRecurring.md +20 -0
- data/docs/SubscriptionStats.md +38 -0
- data/docs/UpdateIntegration.md +20 -0
- data/docs/UpdateLicense.md +3 -1
- data/docs/UpdatePolicy.md +3 -1
- data/docs/UpdateProduct.md +3 -1
- data/lib/license_manager/api/integrations_api.rb +74 -0
- data/lib/license_manager/api/licenses_api.rb +80 -6
- data/lib/license_manager/api/machines_api.rb +3 -3
- data/lib/license_manager/api/portal_api.rb +72 -2
- data/lib/license_manager/api/products_api.rb +4 -4
- data/lib/license_manager/models/billing_portal_session.rb +178 -0
- data/lib/license_manager/models/cancel_license.rb +238 -0
- data/lib/license_manager/models/cancellation_reason.rb +45 -0
- data/lib/license_manager/models/cancellation_stats.rb +347 -0
- data/lib/license_manager/models/cancellation_stats_by_reason_inner.rb +225 -0
- data/lib/license_manager/models/connect_stripe.rb +1 -1
- data/lib/license_manager/models/create_billing_portal_session.rb +161 -0
- data/lib/license_manager/models/create_integration_mapping.rb +1 -1
- data/lib/license_manager/models/create_license.rb +12 -1
- data/lib/license_manager/models/create_policy.rb +40 -5
- data/lib/license_manager/models/create_product_with_policy.rb +1 -1
- data/lib/license_manager/models/create_token.rb +1 -1
- data/lib/license_manager/models/event_type.rb +7 -1
- data/lib/license_manager/models/integration.rb +136 -1
- data/lib/license_manager/models/integration_mapping.rb +13 -1
- data/lib/license_manager/models/integration_mapping_recurring.rb +228 -0
- data/lib/license_manager/models/license.rb +91 -1
- data/lib/license_manager/models/license_status.rb +2 -1
- data/lib/license_manager/models/license_subscription.rb +388 -0
- data/lib/license_manager/models/machine.rb +17 -4
- data/lib/license_manager/models/mrr.rb +291 -0
- data/lib/license_manager/models/mrr_by_interval_inner.rb +279 -0
- data/lib/license_manager/models/mrr_by_policy_inner.rb +229 -0
- data/lib/license_manager/models/policy.rb +14 -1
- data/lib/license_manager/models/policy_settings.rb +40 -5
- data/lib/license_manager/models/portal_link.rb +1 -1
- data/lib/license_manager/models/product.rb +28 -1
- data/lib/license_manager/models/product_stats.rb +31 -5
- data/lib/license_manager/models/revenue.rb +112 -4
- data/lib/license_manager/models/stripe_integration.rb +1 -1
- data/lib/license_manager/models/stripe_permission.rb +58 -4
- data/lib/license_manager/models/stripe_price.rb +13 -1
- data/lib/license_manager/models/stripe_price_recurring.rb +228 -0
- data/lib/license_manager/models/subscription_stats.rb +456 -0
- data/lib/license_manager/models/update_integration.rb +199 -0
- data/lib/license_manager/models/update_license.rb +16 -5
- data/lib/license_manager/models/update_policy.rb +40 -5
- data/lib/license_manager/models/update_product.rb +14 -4
- data/lib/license_manager/version.rb +1 -1
- data/lib/license_manager.rb +14 -0
- data/openapi.json +1146 -59
- data/spec/api/integrations_api_spec.rb +13 -0
- data/spec/api/licenses_api_spec.rb +16 -3
- data/spec/api/machines_api_spec.rb +1 -1
- data/spec/api/portal_api_spec.rb +14 -1
- data/spec/api/products_api_spec.rb +2 -2
- data/spec/models/billing_portal_session_spec.rb +36 -0
- data/spec/models/cancel_license_spec.rb +48 -0
- data/spec/models/cancellation_reason_spec.rb +30 -0
- data/spec/models/cancellation_stats_by_reason_inner_spec.rb +42 -0
- data/spec/models/cancellation_stats_spec.rb +72 -0
- data/spec/models/create_billing_portal_session_spec.rb +36 -0
- data/spec/models/create_license_spec.rb +6 -0
- data/spec/models/create_policy_spec.rb +6 -0
- data/spec/models/create_token_spec.rb +1 -1
- data/spec/models/integration_mapping_recurring_spec.rb +46 -0
- data/spec/models/integration_mapping_spec.rb +6 -0
- data/spec/models/integration_spec.rb +30 -0
- data/spec/models/license_spec.rb +36 -0
- data/spec/models/license_subscription_spec.rb +88 -0
- data/spec/models/machine_spec.rb +7 -1
- data/spec/models/mrr_by_interval_inner_spec.rb +58 -0
- data/spec/models/mrr_by_policy_inner_spec.rb +48 -0
- data/spec/models/mrr_spec.rb +60 -0
- data/spec/models/policy_settings_spec.rb +6 -0
- data/spec/models/policy_spec.rb +6 -0
- data/spec/models/product_spec.rb +6 -0
- data/spec/models/product_stats_spec.rb +12 -0
- data/spec/models/revenue_spec.rb +24 -0
- data/spec/models/stripe_permission_spec.rb +12 -0
- data/spec/models/stripe_price_recurring_spec.rb +46 -0
- data/spec/models/stripe_price_spec.rb +6 -0
- data/spec/models/subscription_stats_spec.rb +96 -0
- data/spec/models/token_spec.rb +1 -1
- data/spec/models/update_integration_spec.rb +42 -0
- data/spec/models/update_license_spec.rb +6 -0
- data/spec/models/update_policy_spec.rb +6 -0
- data/spec/models/update_product_spec.rb +6 -0
- metadata +57 -1
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# LicenseManager::LicenseSubscription
|
|
2
|
+
|
|
3
|
+
## Properties
|
|
4
|
+
|
|
5
|
+
| Name | Type | Description | Notes |
|
|
6
|
+
| ---- | ---- | ----------- | ----- |
|
|
7
|
+
| **stripe_subscription_id** | **String** | | |
|
|
8
|
+
| **status** | **String** | Status of the subscription in Stripe: `active`, `trialing`, `past_due` while a failed payment is retried, `canceled`, `unpaid`, `paused`, `incomplete` or `incomplete_expired`. | |
|
|
9
|
+
| **interval** | **String** | | |
|
|
10
|
+
| **interval_count** | **Integer** | Number of intervals between payments. | |
|
|
11
|
+
| **quantity** | **Integer** | Units subscribed, multiplying the policy's machines. | |
|
|
12
|
+
| **price** | [**Price**](Price.md) | Price of one unit for one period, before taxes. | |
|
|
13
|
+
| **current_period_end** | **Time** | End of the paid period, when the subscription renews or ends. | |
|
|
14
|
+
| **cancel_at_period_end** | **Boolean** | Whether the subscription ends at the end of the period. | |
|
|
15
|
+
| **ended_at** | **Time** | | |
|
|
16
|
+
|
|
17
|
+
## Example
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
require 'license_manager'
|
|
21
|
+
|
|
22
|
+
instance = LicenseManager::LicenseSubscription.new(
|
|
23
|
+
stripe_subscription_id: sub_1MowQVLkdIwHu7ix,
|
|
24
|
+
status: active,
|
|
25
|
+
interval: null,
|
|
26
|
+
interval_count: 1,
|
|
27
|
+
quantity: 1,
|
|
28
|
+
price: null,
|
|
29
|
+
current_period_end: null,
|
|
30
|
+
cancel_at_period_end: null,
|
|
31
|
+
ended_at: null
|
|
32
|
+
)
|
|
33
|
+
```
|
|
34
|
+
|
data/docs/LicensesApi.md
CHANGED
|
@@ -4,6 +4,7 @@ All URIs are relative to *https://api.licensemanager.dev*
|
|
|
4
4
|
|
|
5
5
|
| Method | HTTP request | Description |
|
|
6
6
|
| ------ | ------------ | ----------- |
|
|
7
|
+
| [**cancel_license**](LicensesApi.md#cancel_license) | **POST** /v1/licenses/{id}/cancel | Cancel a license |
|
|
7
8
|
| [**create_license**](LicensesApi.md#create_license) | **POST** /v1/products/{productId}/licenses | Create a license |
|
|
8
9
|
| [**delete_license**](LicensesApi.md#delete_license) | **DELETE** /v1/licenses/{id} | Delete a license |
|
|
9
10
|
| [**get_license**](LicensesApi.md#get_license) | **GET** /v1/licenses/{id} | Get a license |
|
|
@@ -16,13 +17,89 @@ All URIs are relative to *https://api.licensemanager.dev*
|
|
|
16
17
|
| [**validate_key**](LicensesApi.md#validate_key) | **POST** /v1/products/{productId}/validate-key | Validate a license key |
|
|
17
18
|
|
|
18
19
|
|
|
20
|
+
## cancel_license
|
|
21
|
+
|
|
22
|
+
> <License> cancel_license(id, cancel_license)
|
|
23
|
+
|
|
24
|
+
Cancel a license
|
|
25
|
+
|
|
26
|
+
Cancels the license right away: validating its key then fails with `license_expired`, like an expired license, and its status is `canceled`. A cancellation can't be undone. Customers can cancel their licenses until their `cancellableUntil`, the end of their money back guarantee: tokens can't cancel a license past it, or without one. API keys and sessions can cancel any license. When the license was bought through the Stripe integration, its payment is refunded in the background, unless the integration disables `autoRefund`, its API key lacks the optional Refunds: Write permission (`canRefund`), or `refund` is `false`: the refund is its price paid, taxes included, and its id is set as `stripeRefundId`. The customer is emailed a confirmation, and the owners and admins of the organization are told about the cancellation and its refund. In test products, the customer is only emailed when their email is a member's of the organization. A subscription license isn't refunded: its Stripe subscription is canceled at once, without proration, which needs the integration's `canManageSubscriptions`. Records a `license.canceled` event, then a `license.refunded` or `license.refund_failed` one once the refund is done. **Token access**: customer, license tokens with the `license:cancel` permission (or the matching write one). A token reaches the license it's scoped to, or the licenses of its customer. **Required role permission**: `license:cancel` when called with a session, granted by the member's role. API keys aren't limited by roles.
|
|
27
|
+
|
|
28
|
+
### Examples
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
require 'time'
|
|
32
|
+
require 'license_manager'
|
|
33
|
+
# setup authorization
|
|
34
|
+
LicenseManager.configure do |config|
|
|
35
|
+
# Configure API key authorization: apiKey
|
|
36
|
+
config.api_key['x-api-key'] = 'YOUR API KEY'
|
|
37
|
+
# Uncomment the following line to set a prefix for the API key, e.g. 'Bearer' (defaults to nil)
|
|
38
|
+
# config.api_key_prefix['x-api-key'] = 'Bearer'
|
|
39
|
+
|
|
40
|
+
# Configure Bearer authorization (JWT): token
|
|
41
|
+
config.access_token = 'YOUR_BEARER_TOKEN'
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
api_instance = LicenseManager::LicensesApi.new
|
|
45
|
+
id = 'l3Nv8KwB' # String |
|
|
46
|
+
cancel_license = LicenseManager::CancelLicense.new({reason: LicenseManager::CancellationReason::TOO_EXPENSIVE}) # CancelLicense |
|
|
47
|
+
|
|
48
|
+
begin
|
|
49
|
+
# Cancel a license
|
|
50
|
+
result = api_instance.cancel_license(id, cancel_license)
|
|
51
|
+
p result
|
|
52
|
+
rescue LicenseManager::ApiError => e
|
|
53
|
+
puts "Error when calling LicensesApi->cancel_license: #{e}"
|
|
54
|
+
end
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
#### Using the cancel_license_with_http_info variant
|
|
58
|
+
|
|
59
|
+
This returns an Array which contains the response data, status code and headers.
|
|
60
|
+
|
|
61
|
+
> <Array(<License>, Integer, Hash)> cancel_license_with_http_info(id, cancel_license)
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
64
|
+
begin
|
|
65
|
+
# Cancel a license
|
|
66
|
+
data, status_code, headers = api_instance.cancel_license_with_http_info(id, cancel_license)
|
|
67
|
+
p status_code # => 2xx
|
|
68
|
+
p headers # => { ... }
|
|
69
|
+
p data # => <License>
|
|
70
|
+
rescue LicenseManager::ApiError => e
|
|
71
|
+
puts "Error when calling LicensesApi->cancel_license_with_http_info: #{e}"
|
|
72
|
+
end
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Parameters
|
|
76
|
+
|
|
77
|
+
| Name | Type | Description | Notes |
|
|
78
|
+
| ---- | ---- | ----------- | ----- |
|
|
79
|
+
| **id** | **String** | | |
|
|
80
|
+
| **cancel_license** | [**CancelLicense**](CancelLicense.md) | | |
|
|
81
|
+
|
|
82
|
+
### Return type
|
|
83
|
+
|
|
84
|
+
[**License**](License.md)
|
|
85
|
+
|
|
86
|
+
### Authorization
|
|
87
|
+
|
|
88
|
+
[apiKey](../README.md#apiKey), [token](../README.md#token)
|
|
89
|
+
|
|
90
|
+
### HTTP request headers
|
|
91
|
+
|
|
92
|
+
- **Content-Type**: application/json
|
|
93
|
+
- **Accept**: application/json
|
|
94
|
+
|
|
95
|
+
|
|
19
96
|
## create_license
|
|
20
97
|
|
|
21
98
|
> <License> create_license(product_id, create_license)
|
|
22
99
|
|
|
23
100
|
Create a license
|
|
24
101
|
|
|
25
|
-
Without a `key`, the license gets a random one, like `7KQ2M-X9ZPA-H4TRC-WN6EY-B3JDF`: 5 groups of 5 characters separated by dashes, each character an upper case letter or a digit other than `O`, `0`, `I` and `1`. That's 32 possible characters encoding 5 bits each, for 125 random bits. Without a `policyId`, the license follows the product's default policy. Without an `expiresAt`, the license expires after the duration of its policy, or never when the policy has none. `expiresAt: null` makes it never expire. Without a `price`, the price paid for the license is unknown: it's left out of the revenue stats. The values of `maxVersion` left out are taken from the max version of the policy: its hard-coded version, or the times after the creation of the license its versions lock. The license belongs to the product's customer with the given `email`, which is created when there's none. With `sendKey: true`, the key is emailed to the customer once the license is created. The license copies the settings of its policy when it's created: later changes to the policy don't affect it. Its key, policy and customer can't be changed afterwards. **Required role permission**: `license:create` when called with a session, granted by the member's role. API keys aren't limited by roles.
|
|
102
|
+
Without a `key`, the license gets a random one, like `7KQ2M-X9ZPA-H4TRC-WN6EY-B3JDF`: 5 groups of 5 characters separated by dashes, each character an upper case letter or a digit other than `O`, `0`, `I` and `1`. That's 32 possible characters encoding 5 bits each, for 125 random bits. Without a `policyId`, the license follows the product's default policy. Without an `expiresAt`, the license expires after the duration of its policy, or never when the policy has none. `expiresAt: null` makes it never expire. Without a `price`, the price paid for the license is unknown: it's left out of the revenue stats. Without a `cancellableUntil`, the customer can cancel the license during the policy's `moneyBackGuaranteeDays` after its creation, or never when the policy has none. The values of `maxVersion` left out are taken from the max version of the policy: its hard-coded version, or the times after the creation of the license its versions lock. The license belongs to the product's customer with the given `email`, which is created when there's none. With `sendKey: true`, the key is emailed to the customer once the license is created. The license copies the settings of its policy when it's created: later changes to the policy don't affect it. Its key, policy and customer can't be changed afterwards. **Required role permission**: `license:create` when called with a session, granted by the member's role. API keys aren't limited by roles.
|
|
26
103
|
|
|
27
104
|
### Examples
|
|
28
105
|
|
|
@@ -683,7 +760,7 @@ nil (empty response body)
|
|
|
683
760
|
|
|
684
761
|
Update a license
|
|
685
762
|
|
|
686
|
-
The key, policy and customer of a license can't be changed: sending them does nothing. The changes apply to the next validations of the key, not to the license tokens `validateKey` already returned, which stay valid until they expire. Lowering `maxMachines` doesn't deactivate machines: the ones already active keep validating, and new ones are refused until enough are deactivated. **Required role permission**: `license:update` when called with a session, granted by the member's role. API keys aren't limited by roles.
|
|
763
|
+
The key, policy and customer of a license can't be changed: sending them does nothing. The changes apply to the next validations of the key, not to the license tokens `validateKey` already returned, which stay valid until they expire. Lowering `maxMachines` doesn't deactivate machines: the ones already active keep validating, and new ones replace them one at a time when the product has `autoMachineChange`, or are refused until enough are deactivated. **Required role permission**: `license:update` when called with a session, granted by the member's role. API keys aren't limited by roles.
|
|
687
764
|
|
|
688
765
|
### Examples
|
|
689
766
|
|
|
@@ -756,7 +833,7 @@ end
|
|
|
756
833
|
|
|
757
834
|
Validate a license key
|
|
758
835
|
|
|
759
|
-
Checks the license key of the product on a machine and returns a token the application can verify offline with the organization's public key. Doesn't need authentication. The license must allow the `version`: up to its `maxVersion.version` when it has one, like `\"2.3\"` for every 2.3.z version and older. Its `maxVersion.lockMajorAt` and `maxVersion.lockMinorAt` are enforced once they hard-code `maxVersion.version`, within the hour they're reached. When it doesn't, the error's `latestAllowedVersion` is the latest release of the product the license allows, so the application can offer to install it. The machine with the `fingerprint` is created when the license has none, and activated when it's deactivated, unless the license is already active on its maximum number of machines. A machine that's already active is never refused for the maximum number of machines, even when it was lowered below the number of active machines. Its `version`, and its `name` and `platform` when given, are updated: they can't be cleared. The checks run in this order, and the first one failing answers: the license has expired, then it doesn't allow the version, then it's on its maximum number of machines. Each failure is recorded as a `license.validation_failed` event, except for keys that don't exist. Changes to the license, like deactivating the machine or shortening its expiration, don't revoke the tokens already returned: the application only sees them when it validates its key again, at the latest when its token expires.
|
|
836
|
+
Checks the license key of the product on a machine and returns a token the application can verify offline with the organization's public key. Doesn't need authentication. The license must allow the `version`: up to its `maxVersion.version` when it has one, like `\"2.3\"` for every 2.3.z version and older. Its `maxVersion.lockMajorAt` and `maxVersion.lockMinorAt` are enforced once they hard-code `maxVersion.version`, within the hour they're reached. When it doesn't, the error's `latestAllowedVersion` is the latest release of the product the license allows, so the application can offer to install it. The machine with the `fingerprint` is created when the license has none, and activated when it's deactivated, unless the license is already active on its maximum number of machines. A machine that's already active is never refused for the maximum number of machines, even when it was lowered below the number of active machines. Its `version`, and its `name` and `platform` when given, are updated: they can't be cleared. Unless the product disables `autoMachineChange`, a new machine isn't refused when the license is on its maximum number of machines: it takes the place of the active machine validated the longest ago, which is deactivated with its `overriddenByMachineId` set to the new machine, and recorded as a `machine.deactivated` event. When a machine deactivated this way is validated again, it takes its place back: the machine that overrode it, and the ones that overrode that one in turn, are locked, with their `overriddenByMachineId` set to the machine coming back. A locked machine is always refused, so two machines can't take turns on one place. The checks run in this order, and the first one failing answers: the license has expired or was canceled, then it doesn't allow the version, then the machine is locked, then it's on its maximum number of machines. Each failure is recorded as a `license.validation_failed` event, except for keys that don't exist. Changes to the license, like deactivating the machine or shortening its expiration, don't revoke the tokens already returned: the application only sees them when it validates its key again, at the latest when its token expires.
|
|
760
837
|
|
|
761
838
|
### Examples
|
|
762
839
|
|
data/docs/Machine.md
CHANGED
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
| **fingerprint** | **String** | Identifies the machine. Unique within the license. | |
|
|
10
10
|
| **platform** | **String** | | |
|
|
11
11
|
| **name** | **String** | | |
|
|
12
|
-
| **status** | **String** | Whether the machine counts as using the license. | |
|
|
12
|
+
| **status** | **String** | Whether the machine counts as using the license. A `locked` machine doesn't, and its validations are refused with `machine_locked`: it overrode a machine that came back. See `validateKey`. | |
|
|
13
13
|
| **version** | **String** | Version of the application last validated on the machine. | |
|
|
14
|
+
| **overridden_by_machine_id** | **String** | For a machine deactivated or locked by automatic machine changes, the machine that took its place. Validating the key on a deactivated machine that has one takes its place back. `null` otherwise. | |
|
|
14
15
|
| **last_validated_at** | **Time** | When the license was last validated on the machine. | |
|
|
15
16
|
| **created_at** | **Time** | | |
|
|
16
17
|
| **updated_at** | **Time** | | |
|
|
@@ -28,6 +29,7 @@ instance = LicenseManager::Machine.new(
|
|
|
28
29
|
name: Jane's MacBook,
|
|
29
30
|
status: active,
|
|
30
31
|
version: 1.4.2,
|
|
32
|
+
overridden_by_machine_id: null,
|
|
31
33
|
last_validated_at: 2026-01-15T09:30:00.000Z,
|
|
32
34
|
created_at: 2026-01-15T09:30:00.000Z,
|
|
33
35
|
updated_at: 2026-01-15T09:30:00.000Z
|
data/docs/MachinesApi.md
CHANGED
|
@@ -15,7 +15,7 @@ All URIs are relative to *https://api.licensemanager.dev*
|
|
|
15
15
|
|
|
16
16
|
Deactivate a machine
|
|
17
17
|
|
|
18
|
-
The machine no longer counts as using the license, freeing its place when the license has a maximum number of machines. Validating the license key on the machine activates it again, unless the license is on its maximum number of machines by then. Deactivating a deactivated machine does nothing. The license token `validateKey` returned to the machine isn't revoked: the application can keep running offline until it expires. Machines can't be deleted: they're deleted with their license. **Token access**: customer, license, machine tokens with the `machine:write` permission (or the matching write one). A token reaches the machine it's scoped to, or the machines of its license or customer. **Required role permission**: `machine:deactivate` when called with a session, granted by the member's role. API keys aren't limited by roles.
|
|
18
|
+
The machine no longer counts as using the license, freeing its place when the license has a maximum number of machines. Validating the license key on the machine activates it again, unless the license is on its maximum number of machines by then. Deactivating a deactivated or locked machine does nothing. The license token `validateKey` returned to the machine isn't revoked: the application can keep running offline until it expires. Machines can't be deleted: they're deleted with their license. **Token access**: customer, license, machine tokens with the `machine:write` permission (or the matching write one). A token reaches the machine it's scoped to, or the machines of its license or customer. **Required role permission**: `machine:deactivate` when called with a session, granted by the member's role. API keys aren't limited by roles.
|
|
19
19
|
|
|
20
20
|
### Examples
|
|
21
21
|
|
data/docs/Mrr.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# LicenseManager::Mrr
|
|
2
|
+
|
|
3
|
+
## Properties
|
|
4
|
+
|
|
5
|
+
| Name | Type | Description | Notes |
|
|
6
|
+
| ---- | ---- | ----------- | ----- |
|
|
7
|
+
| **currency** | **String** | | |
|
|
8
|
+
| **mrr** | **Float** | Monthly recurring revenue: the price of every ongoing subscription in the currency, times its quantity, brought to one month (a year counts for a twelfth), before taxes and discounts. | |
|
|
9
|
+
| **by_interval** | [**Array<MrrByIntervalInner>**](MrrByIntervalInner.md) | Ongoing subscriptions and MRR of each billing period, like monthly and yearly, from the highest MRR. | |
|
|
10
|
+
| **by_policy** | [**Array<MrrByPolicyInner>**](MrrByPolicyInner.md) | MRR of each policy, from the highest. | |
|
|
11
|
+
| **by_month** | **Array<Float>** | MRR at the end of each month, aligned on `months`, today for this month, at the current prices of the subscriptions. | |
|
|
12
|
+
|
|
13
|
+
## Example
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
require 'license_manager'
|
|
17
|
+
|
|
18
|
+
instance = LicenseManager::Mrr.new(
|
|
19
|
+
currency: USD,
|
|
20
|
+
mrr: 1240,
|
|
21
|
+
by_interval: null,
|
|
22
|
+
by_policy: null,
|
|
23
|
+
by_month: [900, 1100, 1240]
|
|
24
|
+
)
|
|
25
|
+
```
|
|
26
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# LicenseManager::MrrByIntervalInner
|
|
2
|
+
|
|
3
|
+
## Properties
|
|
4
|
+
|
|
5
|
+
| Name | Type | Description | Notes |
|
|
6
|
+
| ---- | ---- | ----------- | ----- |
|
|
7
|
+
| **interval** | **String** | | |
|
|
8
|
+
| **interval_count** | **Integer** | | |
|
|
9
|
+
| **subscription_count** | **Integer** | | |
|
|
10
|
+
| **mrr** | **Float** | | |
|
|
11
|
+
|
|
12
|
+
## Example
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
require 'license_manager'
|
|
16
|
+
|
|
17
|
+
instance = LicenseManager::MrrByIntervalInner.new(
|
|
18
|
+
interval: null,
|
|
19
|
+
interval_count: 1,
|
|
20
|
+
subscription_count: 80,
|
|
21
|
+
mrr: 800
|
|
22
|
+
)
|
|
23
|
+
```
|
|
24
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# LicenseManager::MrrByPolicyInner
|
|
2
|
+
|
|
3
|
+
## Properties
|
|
4
|
+
|
|
5
|
+
| Name | Type | Description | Notes |
|
|
6
|
+
| ---- | ---- | ----------- | ----- |
|
|
7
|
+
| **policy_id** | **String** | | |
|
|
8
|
+
| **subscription_count** | **Integer** | | |
|
|
9
|
+
| **mrr** | **Float** | | |
|
|
10
|
+
|
|
11
|
+
## Example
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
require 'license_manager'
|
|
15
|
+
|
|
16
|
+
instance = LicenseManager::MrrByPolicyInner.new(
|
|
17
|
+
policy_id: p4Rt8LmQ,
|
|
18
|
+
subscription_count: 80,
|
|
19
|
+
mrr: 800
|
|
20
|
+
)
|
|
21
|
+
```
|
|
22
|
+
|
data/docs/Policy.md
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
| **max_machines** | **Integer** | Maximum number of active machines of the licenses created with this policy. `null` when there's no limit. | |
|
|
14
14
|
| **max_offline_duration_seconds** | **Integer** | Longest the applications can run offline with the licenses created with this policy, in seconds. | |
|
|
15
15
|
| **max_version** | [**PolicyMaxVersion**](PolicyMaxVersion.md) | | |
|
|
16
|
+
| **money_back_guarantee_days** | **Integer** | Number of days after their creation during which customers can cancel the licenses created with this policy, from the customer portal or with `cancelLicense`. `null` when they can't. | |
|
|
16
17
|
| **license_count** | **Integer** | Number of licenses following this policy. | |
|
|
17
18
|
| **created_at** | **Time** | | |
|
|
18
19
|
| **updated_at** | **Time** | | |
|
|
@@ -32,6 +33,7 @@ instance = LicenseManager::Policy.new(
|
|
|
32
33
|
max_machines: 3,
|
|
33
34
|
max_offline_duration_seconds: 604800,
|
|
34
35
|
max_version: null,
|
|
36
|
+
money_back_guarantee_days: 30,
|
|
35
37
|
license_count: 12,
|
|
36
38
|
created_at: 2026-01-15T09:30:00.000Z,
|
|
37
39
|
updated_at: 2026-01-15T09:30:00.000Z
|
data/docs/PolicySettings.md
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
| **max_machines** | **Integer** | Maximum number of active machines of the licenses created with this policy, copied to each of them. `null` for no limit. Defaults to `null`. | [optional] |
|
|
9
9
|
| **max_offline_duration_seconds** | **Integer** | Longest the applications can run offline with the licenses created with this policy, in seconds, copied to each of them. At least one hour (`3600`). Defaults to one week. | [optional] |
|
|
10
10
|
| **max_version** | [**PolicySettingsMaxVersion**](PolicySettingsMaxVersion.md) | | [optional] |
|
|
11
|
+
| **money_back_guarantee_days** | **Integer** | Number of days after their creation during which customers can cancel the licenses created with this policy, from the customer portal or with `cancelLicense`, which refunds their Stripe payment. Each license keeps the end of its own period as `cancellableUntil`. `null` for no money back guarantee. Defaults to `null`. | [optional] |
|
|
11
12
|
|
|
12
13
|
## Example
|
|
13
14
|
|
|
@@ -18,7 +19,8 @@ instance = LicenseManager::PolicySettings.new(
|
|
|
18
19
|
duration: null,
|
|
19
20
|
max_machines: 3,
|
|
20
21
|
max_offline_duration_seconds: 604800,
|
|
21
|
-
max_version: null
|
|
22
|
+
max_version: null,
|
|
23
|
+
money_back_guarantee_days: 30
|
|
22
24
|
)
|
|
23
25
|
```
|
|
24
26
|
|
data/docs/PortalApi.md
CHANGED
|
@@ -4,19 +4,98 @@ All URIs are relative to *https://api.licensemanager.dev*
|
|
|
4
4
|
|
|
5
5
|
| Method | HTTP request | Description |
|
|
6
6
|
| ------ | ------------ | ----------- |
|
|
7
|
+
| [**create_billing_portal_session**](PortalApi.md#create_billing_portal_session) | **POST** /v1/customers/{id}/billing-portal-sessions | Open the Stripe customer portal of a customer |
|
|
7
8
|
| [**create_portal_link**](PortalApi.md#create_portal_link) | **POST** /v1/customers/{id}/portal-links | Create a link to the customer portal |
|
|
8
9
|
| [**get_portal**](PortalApi.md#get_portal) | **GET** /v1/portal/{productId} | Get the customer portal of a product |
|
|
9
10
|
| [**request_portal_link**](PortalApi.md#request_portal_link) | **POST** /v1/portal/{productId}/request-link | Email a link to the customer portal |
|
|
10
11
|
| [**send_portal_link**](PortalApi.md#send_portal_link) | **POST** /v1/customers/{id}/portal-links/send | Email a link to the customer portal to the customer |
|
|
11
12
|
|
|
12
13
|
|
|
14
|
+
## create_billing_portal_session
|
|
15
|
+
|
|
16
|
+
> <BillingPortalSession> create_billing_portal_session(id, opts)
|
|
17
|
+
|
|
18
|
+
Open the Stripe customer portal of a customer
|
|
19
|
+
|
|
20
|
+
Link to the Stripe customer portal of the customer's Stripe customer, where they manage their subscriptions: change their plan or payment method, see their invoices, cancel. Needs the Stripe integration's `canBillingPortal`, and the customer portal configured in the Stripe account's settings. The changes come back through the integration's webhook, keeping the subscription licenses in line. **Token access**: customer tokens with the `customer:billing` permission (or the matching write one). A customer token reaches its own customer. **Required role permission**: `portalLink:create` when called with a session, granted by the member's role. API keys aren't limited by roles.
|
|
21
|
+
|
|
22
|
+
### Examples
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
require 'time'
|
|
26
|
+
require 'license_manager'
|
|
27
|
+
# setup authorization
|
|
28
|
+
LicenseManager.configure do |config|
|
|
29
|
+
# Configure API key authorization: apiKey
|
|
30
|
+
config.api_key['x-api-key'] = 'YOUR API KEY'
|
|
31
|
+
# Uncomment the following line to set a prefix for the API key, e.g. 'Bearer' (defaults to nil)
|
|
32
|
+
# config.api_key_prefix['x-api-key'] = 'Bearer'
|
|
33
|
+
|
|
34
|
+
# Configure Bearer authorization (JWT): token
|
|
35
|
+
config.access_token = 'YOUR_BEARER_TOKEN'
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
api_instance = LicenseManager::PortalApi.new
|
|
39
|
+
id = 'c9Wd3RtE' # String |
|
|
40
|
+
opts = {
|
|
41
|
+
create_billing_portal_session: LicenseManager::CreateBillingPortalSession.new # CreateBillingPortalSession |
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
begin
|
|
45
|
+
# Open the Stripe customer portal of a customer
|
|
46
|
+
result = api_instance.create_billing_portal_session(id, opts)
|
|
47
|
+
p result
|
|
48
|
+
rescue LicenseManager::ApiError => e
|
|
49
|
+
puts "Error when calling PortalApi->create_billing_portal_session: #{e}"
|
|
50
|
+
end
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
#### Using the create_billing_portal_session_with_http_info variant
|
|
54
|
+
|
|
55
|
+
This returns an Array which contains the response data, status code and headers.
|
|
56
|
+
|
|
57
|
+
> <Array(<BillingPortalSession>, Integer, Hash)> create_billing_portal_session_with_http_info(id, opts)
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
begin
|
|
61
|
+
# Open the Stripe customer portal of a customer
|
|
62
|
+
data, status_code, headers = api_instance.create_billing_portal_session_with_http_info(id, opts)
|
|
63
|
+
p status_code # => 2xx
|
|
64
|
+
p headers # => { ... }
|
|
65
|
+
p data # => <BillingPortalSession>
|
|
66
|
+
rescue LicenseManager::ApiError => e
|
|
67
|
+
puts "Error when calling PortalApi->create_billing_portal_session_with_http_info: #{e}"
|
|
68
|
+
end
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Parameters
|
|
72
|
+
|
|
73
|
+
| Name | Type | Description | Notes |
|
|
74
|
+
| ---- | ---- | ----------- | ----- |
|
|
75
|
+
| **id** | **String** | | |
|
|
76
|
+
| **create_billing_portal_session** | [**CreateBillingPortalSession**](CreateBillingPortalSession.md) | | [optional] |
|
|
77
|
+
|
|
78
|
+
### Return type
|
|
79
|
+
|
|
80
|
+
[**BillingPortalSession**](BillingPortalSession.md)
|
|
81
|
+
|
|
82
|
+
### Authorization
|
|
83
|
+
|
|
84
|
+
[apiKey](../README.md#apiKey), [token](../README.md#token)
|
|
85
|
+
|
|
86
|
+
### HTTP request headers
|
|
87
|
+
|
|
88
|
+
- **Content-Type**: application/json
|
|
89
|
+
- **Accept**: application/json
|
|
90
|
+
|
|
91
|
+
|
|
13
92
|
## create_portal_link
|
|
14
93
|
|
|
15
94
|
> <PortalLink> create_portal_link(id, create_portal_link)
|
|
16
95
|
|
|
17
96
|
Create a link to the customer portal
|
|
18
97
|
|
|
19
|
-
Link letting the customer see their licenses and deactivate their machines in the customer portal, without signing in. Anyone with the link can, until it expires or the customer is deleted: it can't be revoked otherwise. The token also works with the API endpoints that accept customer tokens. Links can be created while the product's customer portal is disabled, but the portal answers `404` until it's enabled, and `sendPortalLink` refuses to email them. **Required role permission**: `portalLink:create` when called with a session, granted by the member's role. API keys aren't limited by roles.
|
|
98
|
+
Link letting the customer see their licenses, cancel them during their money back guarantee, and deactivate their machines in the customer portal, without signing in. Anyone with the link can, until it expires or the customer is deleted: it can't be revoked otherwise. The token also works with the API endpoints that accept customer tokens. Links can be created while the product's customer portal is disabled, but the portal answers `404` until it's enabled, and `sendPortalLink` refuses to email them. **Required role permission**: `portalLink:create` when called with a session, granted by the member's role. API keys aren't limited by roles.
|
|
20
99
|
|
|
21
100
|
### Examples
|
|
22
101
|
|
data/docs/PortalLink.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
| Name | Type | Description | Notes |
|
|
6
6
|
| ---- | ---- | ----------- | ----- |
|
|
7
7
|
| **url** | **String** | Link to the customer portal, holding the token. | |
|
|
8
|
-
| **token** | **String** | Customer token in the link, with the `customer:read`, `license:read` and `machine:write` permissions. | |
|
|
8
|
+
| **token** | **String** | Customer token in the link, with the `customer:read`, `license:read`, `license:cancel` and `machine:write` permissions. | |
|
|
9
9
|
| **expires_at** | **Time** | When the link stops working. | |
|
|
10
10
|
|
|
11
11
|
## Example
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
require 'license_manager'
|
|
15
15
|
|
|
16
16
|
instance = LicenseManager::PortalLink.new(
|
|
17
|
-
url: https://app.
|
|
17
|
+
url: https://app.licensemanager.dev/portal/x7Kp2QaZ?token=eyJhbGciOi…,
|
|
18
18
|
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…,
|
|
19
19
|
expires_at: 2026-01-22T09:30:00.000Z
|
|
20
20
|
)
|
data/docs/Product.md
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
| **is_test_from_product_id** | **String** | For test products, id of the live product they're a sandbox of. `null` for live products. | |
|
|
11
11
|
| **logo_url** | **String** | Public URL of the product's logo, shown in the web app and the customer portal. `null` without a logo. | |
|
|
12
12
|
| **portal** | [**PortalSettings**](PortalSettings.md) | | |
|
|
13
|
+
| **auto_machine_change** | **Boolean** | Whether a new machine validating a license already on its max machines takes the place of the license's machine validated the longest ago, rather than being refused with `machine_limit_reached`. When the replaced machine is validated again, it takes its place back and the machine that replaced it is locked. See `validateKey`. | |
|
|
13
14
|
| **created_at** | **Time** | | |
|
|
14
15
|
| **updated_at** | **Time** | | |
|
|
15
16
|
|
|
@@ -25,6 +26,7 @@ instance = LicenseManager::Product.new(
|
|
|
25
26
|
is_test_from_product_id: null,
|
|
26
27
|
logo_url: https://cdn.example.com/logos/x7Kp2QaZ/k3f9a2LpQ7xw.webp,
|
|
27
28
|
portal: null,
|
|
29
|
+
auto_machine_change: true,
|
|
28
30
|
created_at: 2026-01-15T09:30:00.000Z,
|
|
29
31
|
updated_at: 2026-01-15T09:30:00.000Z
|
|
30
32
|
)
|
data/docs/ProductStats.md
CHANGED
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
| Name | Type | Description | Notes |
|
|
6
6
|
| ---- | ---- | ----------- | ----- |
|
|
7
7
|
| **license_count** | **Integer** | Number of licenses of the product. | |
|
|
8
|
-
| **active_license_count** | **Integer** | Number of licenses that haven't expired, and that a machine validated in the last 90 days. | |
|
|
8
|
+
| **active_license_count** | **Integer** | Number of licenses that haven't expired nor were canceled, and that a machine validated in the last 90 days. | |
|
|
9
9
|
| **new_license_count** | **Integer** | Number of licenses created in the last 30 days, today included, in UTC. | |
|
|
10
|
-
| **expiring_license_count** | **Integer** | Number of licenses expiring in the next 30 days. | |
|
|
11
|
-
| **expired_license_count** | **Integer** | Number of licenses that expired in the last 30 days. | |
|
|
10
|
+
| **expiring_license_count** | **Integer** | Number of licenses expiring in the next 30 days, canceled ones left out. | |
|
|
11
|
+
| **expired_license_count** | **Integer** | Number of licenses that expired in the last 30 days, canceled ones left out. | |
|
|
12
12
|
| **active_machine_count** | **Integer** | Number of active machines of the licenses of the product. | |
|
|
13
13
|
| **in_use_license_count** | **Integer** | Number of licenses with at least one active machine. | |
|
|
14
|
-
| **seat_count** | **Integer** | Sum of the maximum numbers of machines of the licenses that haven't expired. Licenses without a maximum are left out. | |
|
|
14
|
+
| **seat_count** | **Integer** | Sum of the maximum numbers of machines of the licenses that haven't expired nor were canceled. Licenses without a maximum are left out. | |
|
|
15
15
|
| **used_seat_count** | **Integer** | Number of active machines of the licenses counted in `seatCount`, at most their maximum number of machines each. | |
|
|
16
16
|
| **full_license_count** | **Integer** | Number of licenses counted in `seatCount` active on their maximum number of machines. | |
|
|
17
17
|
| **days** | **Array<Date>** | The 30 days covered by the daily stats, from the oldest one, in UTC. | |
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
| **new_licenses_by_day** | **Array<Integer>** | Number of licenses created each day, aligned on `days`. | |
|
|
20
20
|
| **new_licenses_by_month** | **Array<Integer>** | Number of licenses created each month, aligned on `months`. | |
|
|
21
21
|
| **new_licenses_by_policy** | [**Array<ProductStatsNewLicensesByPolicyInner>**](ProductStatsNewLicensesByPolicyInner.md) | Number of licenses of each policy created each day and each month, for the policies with licenses created over the covered months. | |
|
|
22
|
+
| **cancellation** | [**CancellationStats**](CancellationStats.md) | Cancellations of the licenses with a money back guarantee. `null` when no license of the product has one. | |
|
|
23
|
+
| **subscriptions** | [**SubscriptionStats**](SubscriptionStats.md) | Subscriptions of the product. `null` when it has never had one. | |
|
|
22
24
|
| **revenue** | [**Array<Revenue>**](Revenue.md) | Revenue in each currency licenses were sold in, from the one with the most licenses sold. Amounts aren't converted between currencies. | |
|
|
23
25
|
| **activations_by_version** | [**Array<ProductStatsActivationsByVersionInner>**](ProductStatsActivationsByVersionInner.md) | Successful activations of the licenses of the product each day, per version of the application, from the most recent one. | |
|
|
24
26
|
| **active_machines_by_version** | [**Array<ProductStatsActiveMachinesByVersionInner>**](ProductStatsActiveMachinesByVersionInner.md) | Number of active machines running each version of the application, from the most recent one. | |
|
|
@@ -45,6 +47,8 @@ instance = LicenseManager::ProductStats.new(
|
|
|
45
47
|
new_licenses_by_day: [0, 2, 1],
|
|
46
48
|
new_licenses_by_month: [4, 9, 12],
|
|
47
49
|
new_licenses_by_policy: null,
|
|
50
|
+
cancellation: null,
|
|
51
|
+
subscriptions: null,
|
|
48
52
|
revenue: null,
|
|
49
53
|
activations_by_version: null,
|
|
50
54
|
active_machines_by_version: null,
|
data/docs/ProductsApi.md
CHANGED
|
@@ -21,7 +21,7 @@ All URIs are relative to *https://api.licensemanager.dev*
|
|
|
21
21
|
|
|
22
22
|
Create a product
|
|
23
23
|
|
|
24
|
-
Without a `slug`, the product gets one derived from its name: lower cased, without accents and special characters (`Élan Pro 2!` becomes `elan-pro-2`). When another product of the organization already uses it, a dash and 3 random lowercase letters or digits are appended (`elan-pro-2-k3f`), until the slug is free. An explicit `slug` is used as is: the request fails with a `409` when it's taken, it's never changed. Slug uniqueness is enforced by the database, so when concurrent requests end up with the same slug, only one succeeds and the others get a `409`, even without an explicit `slug`. Retrying such a request without a `slug` derives a new one. The product is created with its default policy, named `Default policy` with the `default` slug, whose settings are given by `defaultPolicy`. Omitted settings default to licenses that never expire, on a single machine, offline for one week, for every version of the product. Unlike `createPolicy`, where `maxMachines` defaults to no limit. With `isTestFromProductId`, the product is a test product: its id, its slug, and the ids, slugs and license keys of its resources start with `test_` (`TEST-` for license keys), and only test API keys reach it. It starts with copies of the policies, releases
|
|
24
|
+
Without a `slug`, the product gets one derived from its name: lower cased, without accents and special characters (`Élan Pro 2!` becomes `elan-pro-2`). When another product of the organization already uses it, a dash and 3 random lowercase letters or digits are appended (`elan-pro-2-k3f`), until the slug is free. An explicit `slug` is used as is: the request fails with a `409` when it's taken, it's never changed. Slug uniqueness is enforced by the database, so when concurrent requests end up with the same slug, only one succeeds and the others get a `409`, even without an explicit `slug`. Retrying such a request without a `slug` derives a new one. The product is created with its default policy, named `Default policy` with the `default` slug, whose settings are given by `defaultPolicy`. Omitted settings default to licenses that never expire, on a single machine, offline for one week, for every version of the product. Unlike `createPolicy`, where `maxMachines` defaults to no limit. With `isTestFromProductId`, the product is a test product: its id, its slug, and the ids, slugs and license keys of its resources start with `test_` (`TEST-` for license keys), and only test API keys reach it. It starts with copies of the policies, releases, portal settings and `autoMachineChange` of the live product, `defaultPolicy` is ignored. Later changes to the live product aren't copied: reset the test product to copy them again. Test API keys can only create test products, live API keys only live ones. **Required role permission**: `product:create` when called with a session, granted by the member's role. API keys aren't limited by roles.
|
|
25
25
|
|
|
26
26
|
### Examples
|
|
27
27
|
|
|
@@ -454,7 +454,7 @@ end
|
|
|
454
454
|
|
|
455
455
|
Reset a test product
|
|
456
456
|
|
|
457
|
-
Deletes the customers, licenses, machines, policies and releases of the test product, with their events, then copies the policies, releases
|
|
457
|
+
Deletes the customers, licenses, machines, policies and releases of the test product, with their events, then copies the policies, releases, portal settings and `autoMachineChange` of its live product again. Its id, name and slug are kept, but the copied policies get new ids. The tokens of its customers, licenses and machines stop working. **Required role permission**: `product:update` when called with a session, granted by the member's role. API keys aren't limited by roles.
|
|
458
458
|
|
|
459
459
|
### Examples
|
|
460
460
|
|
data/docs/Revenue.md
CHANGED
|
@@ -5,8 +5,12 @@
|
|
|
5
5
|
| Name | Type | Description | Notes |
|
|
6
6
|
| ---- | ---- | ----------- | ----- |
|
|
7
7
|
| **currency** | **String** | ISO 4217 code of the currency of the revenue. | |
|
|
8
|
-
| **license_count** | **Integer** | Number of licenses sold in the currency, free ones included. | |
|
|
9
|
-
| **total** | **Float** |
|
|
8
|
+
| **license_count** | **Integer** | Number of licenses sold once in the currency, free ones included, canceled ones and subscription licenses left out. | |
|
|
9
|
+
| **total** | **Float** | Revenue in the currency, in major units: the prices of the licenses sold once, canceled ones left out, plus the payments of the subscriptions, `subscriptionTotal`. | |
|
|
10
|
+
| **subscription_total** | **Float** | Sum of the payments of the subscription licenses in the currency, before taxes, in major units. | |
|
|
11
|
+
| **payment_count** | **Integer** | Number of payments of the subscription licenses in the currency. | |
|
|
12
|
+
| **canceled_license_count** | **Integer** | Number of canceled licenses sold once in the currency. | |
|
|
13
|
+
| **canceled_total** | **Float** | Sum of the prices of the canceled licenses sold once in the currency, in major units: revenue lost to cancellations. | |
|
|
10
14
|
| **this_month** | **Float** | Revenue of the current month, in UTC. | |
|
|
11
15
|
| **last_month** | **Float** | Revenue of the previous month, in UTC. | |
|
|
12
16
|
| **last30_days** | **Float** | Revenue of the last 30 days, today included, in UTC. | |
|
|
@@ -23,6 +27,10 @@ instance = LicenseManager::Revenue.new(
|
|
|
23
27
|
currency: USD,
|
|
24
28
|
license_count: 42,
|
|
25
29
|
total: 2099.58,
|
|
30
|
+
subscription_total: 480,
|
|
31
|
+
payment_count: 48,
|
|
32
|
+
canceled_license_count: 2,
|
|
33
|
+
canceled_total: 99.98,
|
|
26
34
|
this_month: 349.93,
|
|
27
35
|
last_month: 299.94,
|
|
28
36
|
last30_days: 399.92,
|
data/docs/StripeIntegration.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
| ---- | ---- | ----------- | ----- |
|
|
7
7
|
| **livemode** | **Boolean** | Mode of the Stripe connection the product uses: live for live products, test for test products. | |
|
|
8
8
|
| **webhook_url_reachable** | **Boolean** | Whether Stripe can reach the API's webhook URL. A local URL can't be: set `WEBHOOK_URL` on the server, like to a tunnel in development. | |
|
|
9
|
-
| **required_permissions** | [**Array<StripePermission>**](StripePermission.md) | Permissions the restricted API key needs, and why. Every other permission can stay `None`. | |
|
|
9
|
+
| **required_permissions** | [**Array<StripePermission>**](StripePermission.md) | Permissions the restricted API key needs, and why, the `optional` ones included. Every other permission can stay `None`. | |
|
|
10
10
|
| **integration** | [**Integration**](Integration.md) | The organization's Stripe connection in this mode, `null` when there's none. | |
|
|
11
11
|
| **mappings** | [**Array<IntegrationMapping>**](IntegrationMapping.md) | Stripe prices creating licenses of the product. | |
|
|
12
12
|
|
data/docs/StripePermission.md
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
| **resource** | **String** | | |
|
|
8
8
|
| **access** | **String** | | |
|
|
9
9
|
| **reason** | **String** | | |
|
|
10
|
+
| **optional** | **Boolean** | Whether the key can connect without it, losing what it's for, explained by `reason`. | |
|
|
11
|
+
| **subscriptions** | **Boolean** | Whether it's only needed to sell subscriptions: checked once a recurring price is mapped. | |
|
|
10
12
|
|
|
11
13
|
## Example
|
|
12
14
|
|
|
@@ -16,7 +18,9 @@ require 'license_manager'
|
|
|
16
18
|
instance = LicenseManager::StripePermission.new(
|
|
17
19
|
resource: Prices,
|
|
18
20
|
access: null,
|
|
19
|
-
reason: Lists your prices so you can choose which ones create licenses, and checks they can still be paid
|
|
21
|
+
reason: Lists your prices so you can choose which ones create licenses, and checks they can still be paid.,
|
|
22
|
+
optional: false,
|
|
23
|
+
subscriptions: false
|
|
20
24
|
)
|
|
21
25
|
```
|
|
22
26
|
|
data/docs/StripePrice.md
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
| **product_name** | **String** | | |
|
|
10
10
|
| **nickname** | **String** | | |
|
|
11
11
|
| **price** | [**Price**](Price.md) | | |
|
|
12
|
+
| **recurring** | [**StripePriceRecurring**](StripePriceRecurring.md) | | |
|
|
12
13
|
| **mapped** | **Boolean** | Whether the price already creates licenses of a product. | |
|
|
13
14
|
|
|
14
15
|
## Example
|
|
@@ -22,6 +23,7 @@ instance = LicenseManager::StripePrice.new(
|
|
|
22
23
|
product_name: Acme Pro,
|
|
23
24
|
nickname: Launch price,
|
|
24
25
|
price: null,
|
|
26
|
+
recurring: null,
|
|
25
27
|
mapped: null
|
|
26
28
|
)
|
|
27
29
|
```
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# LicenseManager::StripePriceRecurring
|
|
2
|
+
|
|
3
|
+
## Properties
|
|
4
|
+
|
|
5
|
+
| Name | Type | Description | Notes |
|
|
6
|
+
| ---- | ---- | ----------- | ----- |
|
|
7
|
+
| **interval** | **String** | | |
|
|
8
|
+
| **interval_count** | **Integer** | | |
|
|
9
|
+
|
|
10
|
+
## Example
|
|
11
|
+
|
|
12
|
+
```ruby
|
|
13
|
+
require 'license_manager'
|
|
14
|
+
|
|
15
|
+
instance = LicenseManager::StripePriceRecurring.new(
|
|
16
|
+
interval: null,
|
|
17
|
+
interval_count: 1
|
|
18
|
+
)
|
|
19
|
+
```
|
|
20
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# LicenseManager::SubscriptionStats
|
|
2
|
+
|
|
3
|
+
## Properties
|
|
4
|
+
|
|
5
|
+
| Name | Type | Description | Notes |
|
|
6
|
+
| ---- | ---- | ----------- | ----- |
|
|
7
|
+
| **active_count** | **Integer** | Number of ongoing subscriptions: `active`, `trialing` or `past_due`. | |
|
|
8
|
+
| **trialing_count** | **Integer** | | |
|
|
9
|
+
| **past_due_count** | **Integer** | Number of them whose renewal failed, as Stripe retries it: their licenses stay valid for the integration's grace days. | |
|
|
10
|
+
| **canceling_count** | **Integer** | Number of them set to end at the end of their period. | |
|
|
11
|
+
| **new_count** | **Integer** | Number of subscriptions started in the last 30 days. | |
|
|
12
|
+
| **ended_count** | **Integer** | Number of subscriptions that ended in the last 30 days. | |
|
|
13
|
+
| **churn_rate** | **Float** | Share of the subscriptions ongoing 30 days ago that ended since, from 0 to 1. | |
|
|
14
|
+
| **new_by_month** | **Array<Integer>** | Number of subscriptions started each month, aligned on `months`. | |
|
|
15
|
+
| **ended_by_month** | **Array<Integer>** | Number of subscriptions that ended each month, aligned on `months`. | |
|
|
16
|
+
| **active_by_month** | **Array<Integer>** | Number of ongoing subscriptions at the end of each month, aligned on `months`, today for this month. | |
|
|
17
|
+
| **mrr** | [**Array<Mrr>**](Mrr.md) | MRR in each currency, from the highest number of subscriptions. Amounts aren't converted between currencies. | |
|
|
18
|
+
|
|
19
|
+
## Example
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
require 'license_manager'
|
|
23
|
+
|
|
24
|
+
instance = LicenseManager::SubscriptionStats.new(
|
|
25
|
+
active_count: 120,
|
|
26
|
+
trialing_count: 4,
|
|
27
|
+
past_due_count: 3,
|
|
28
|
+
canceling_count: 5,
|
|
29
|
+
new_count: 14,
|
|
30
|
+
ended_count: 3,
|
|
31
|
+
churn_rate: 0.025,
|
|
32
|
+
new_by_month: [3, 5, 8],
|
|
33
|
+
ended_by_month: [0, 1, 2],
|
|
34
|
+
active_by_month: [90, 104, 120],
|
|
35
|
+
mrr: null
|
|
36
|
+
)
|
|
37
|
+
```
|
|
38
|
+
|