license_manager 0.2.0 → 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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +57 -0
  3. data/README.md +1 -1
  4. data/docs/BillingPortalSession.md +18 -0
  5. data/docs/CreateBillingPortalSession.md +18 -0
  6. data/docs/CreateIntegrationMapping.md +1 -1
  7. data/docs/Integration.md +6 -0
  8. data/docs/IntegrationMapping.md +2 -0
  9. data/docs/IntegrationMappingRecurring.md +20 -0
  10. data/docs/License.md +2 -0
  11. data/docs/LicenseSubscription.md +34 -0
  12. data/docs/LicensesApi.md +1 -1
  13. data/docs/Mrr.md +26 -0
  14. data/docs/MrrByIntervalInner.md +24 -0
  15. data/docs/MrrByPolicyInner.md +22 -0
  16. data/docs/PortalApi.md +79 -0
  17. data/docs/ProductStats.md +2 -0
  18. data/docs/Revenue.md +8 -4
  19. data/docs/StripePermission.md +3 -1
  20. data/docs/StripePrice.md +2 -0
  21. data/docs/StripePriceRecurring.md +20 -0
  22. data/docs/SubscriptionStats.md +38 -0
  23. data/docs/UpdateIntegration.md +3 -1
  24. data/lib/license_manager/api/licenses_api.rb +2 -2
  25. data/lib/license_manager/api/portal_api.rb +70 -0
  26. data/lib/license_manager/models/billing_portal_session.rb +178 -0
  27. data/lib/license_manager/models/create_billing_portal_session.rb +161 -0
  28. data/lib/license_manager/models/create_integration_mapping.rb +1 -1
  29. data/lib/license_manager/models/event_type.rb +4 -1
  30. data/lib/license_manager/models/integration.rb +82 -1
  31. data/lib/license_manager/models/integration_mapping.rb +13 -1
  32. data/lib/license_manager/models/integration_mapping_recurring.rb +228 -0
  33. data/lib/license_manager/models/license.rb +13 -1
  34. data/lib/license_manager/models/license_subscription.rb +388 -0
  35. data/lib/license_manager/models/mrr.rb +291 -0
  36. data/lib/license_manager/models/mrr_by_interval_inner.rb +279 -0
  37. data/lib/license_manager/models/mrr_by_policy_inner.rb +229 -0
  38. data/lib/license_manager/models/product_stats.rb +14 -1
  39. data/lib/license_manager/models/revenue.rb +60 -6
  40. data/lib/license_manager/models/stripe_permission.rb +31 -4
  41. data/lib/license_manager/models/stripe_price.rb +13 -1
  42. data/lib/license_manager/models/stripe_price_recurring.rb +228 -0
  43. data/lib/license_manager/models/subscription_stats.rb +456 -0
  44. data/lib/license_manager/models/update_integration.rb +42 -4
  45. data/lib/license_manager/version.rb +1 -1
  46. data/lib/license_manager.rb +9 -0
  47. data/openapi.json +563 -10
  48. data/spec/api/licenses_api_spec.rb +1 -1
  49. data/spec/api/portal_api_spec.rb +13 -0
  50. data/spec/models/billing_portal_session_spec.rb +36 -0
  51. data/spec/models/create_billing_portal_session_spec.rb +36 -0
  52. data/spec/models/create_token_spec.rb +1 -1
  53. data/spec/models/integration_mapping_recurring_spec.rb +46 -0
  54. data/spec/models/integration_mapping_spec.rb +6 -0
  55. data/spec/models/integration_spec.rb +18 -0
  56. data/spec/models/license_spec.rb +6 -0
  57. data/spec/models/license_subscription_spec.rb +88 -0
  58. data/spec/models/mrr_by_interval_inner_spec.rb +58 -0
  59. data/spec/models/mrr_by_policy_inner_spec.rb +48 -0
  60. data/spec/models/mrr_spec.rb +60 -0
  61. data/spec/models/product_stats_spec.rb +6 -0
  62. data/spec/models/revenue_spec.rb +12 -0
  63. data/spec/models/stripe_permission_spec.rb +6 -0
  64. data/spec/models/stripe_price_recurring_spec.rb +46 -0
  65. data/spec/models/stripe_price_spec.rb +6 -0
  66. data/spec/models/subscription_stats_spec.rb +96 -0
  67. data/spec/models/token_spec.rb +1 -1
  68. data/spec/models/update_integration_spec.rb +6 -0
  69. metadata +37 -1
data/openapi.json CHANGED
@@ -1004,6 +1004,17 @@
1004
1004
  ],
1005
1005
  "description": "Cancellations of the licenses with a money back guarantee. `null` when no license of the product has one."
1006
1006
  },
1007
+ "subscriptions": {
1008
+ "anyOf": [
1009
+ {
1010
+ "$ref": "#/components/schemas/SubscriptionStats"
1011
+ },
1012
+ {
1013
+ "type": "null"
1014
+ }
1015
+ ],
1016
+ "description": "Subscriptions of the product. `null` when it has never had one."
1017
+ },
1007
1018
  "revenue": {
1008
1019
  "type": "array",
1009
1020
  "items": {
@@ -1112,6 +1123,7 @@
1112
1123
  "newLicensesByMonth",
1113
1124
  "newLicensesByPolicy",
1114
1125
  "cancellation",
1126
+ "subscriptions",
1115
1127
  "revenue",
1116
1128
  "activationsByVersion",
1117
1129
  "activeMachinesByVersion",
@@ -1210,6 +1222,197 @@
1210
1222
  "description": "- `too_expensive`: too expensive.\n- `missing_features`: missing features i need.\n- `not_working`: doesn't work as expected.\n- `switched`: found an alternative.\n- `unused`: no longer needed.\n- `other`: other.",
1211
1223
  "example": "too_expensive"
1212
1224
  },
1225
+ "SubscriptionStats": {
1226
+ "type": "object",
1227
+ "properties": {
1228
+ "activeCount": {
1229
+ "type": "integer",
1230
+ "description": "Number of ongoing subscriptions: `active`, `trialing` or `past_due`.",
1231
+ "example": 120
1232
+ },
1233
+ "trialingCount": {
1234
+ "type": "integer",
1235
+ "example": 4
1236
+ },
1237
+ "pastDueCount": {
1238
+ "type": "integer",
1239
+ "description": "Number of them whose renewal failed, as Stripe retries it: their licenses stay valid for the integration's grace days.",
1240
+ "example": 3
1241
+ },
1242
+ "cancelingCount": {
1243
+ "type": "integer",
1244
+ "description": "Number of them set to end at the end of their period.",
1245
+ "example": 5
1246
+ },
1247
+ "newCount": {
1248
+ "type": "integer",
1249
+ "description": "Number of subscriptions started in the last 30 days.",
1250
+ "example": 14
1251
+ },
1252
+ "endedCount": {
1253
+ "type": "integer",
1254
+ "description": "Number of subscriptions that ended in the last 30 days.",
1255
+ "example": 3
1256
+ },
1257
+ "churnRate": {
1258
+ "type": "number",
1259
+ "description": "Share of the subscriptions ongoing 30 days ago that ended since, from 0 to 1.",
1260
+ "example": 0.025
1261
+ },
1262
+ "newByMonth": {
1263
+ "type": "array",
1264
+ "items": {
1265
+ "type": "integer"
1266
+ },
1267
+ "description": "Number of subscriptions started each month, aligned on `months`.",
1268
+ "example": [
1269
+ 3,
1270
+ 5,
1271
+ 8
1272
+ ]
1273
+ },
1274
+ "endedByMonth": {
1275
+ "type": "array",
1276
+ "items": {
1277
+ "type": "integer"
1278
+ },
1279
+ "description": "Number of subscriptions that ended each month, aligned on `months`.",
1280
+ "example": [
1281
+ 0,
1282
+ 1,
1283
+ 2
1284
+ ]
1285
+ },
1286
+ "activeByMonth": {
1287
+ "type": "array",
1288
+ "items": {
1289
+ "type": "integer"
1290
+ },
1291
+ "description": "Number of ongoing subscriptions at the end of each month, aligned on `months`, today for this month.",
1292
+ "example": [
1293
+ 90,
1294
+ 104,
1295
+ 120
1296
+ ]
1297
+ },
1298
+ "mrr": {
1299
+ "type": "array",
1300
+ "items": {
1301
+ "$ref": "#/components/schemas/Mrr"
1302
+ },
1303
+ "description": "MRR in each currency, from the highest number of subscriptions. Amounts aren't converted between currencies."
1304
+ }
1305
+ },
1306
+ "required": [
1307
+ "activeCount",
1308
+ "trialingCount",
1309
+ "pastDueCount",
1310
+ "cancelingCount",
1311
+ "newCount",
1312
+ "endedCount",
1313
+ "churnRate",
1314
+ "newByMonth",
1315
+ "endedByMonth",
1316
+ "activeByMonth",
1317
+ "mrr"
1318
+ ],
1319
+ "description": "Subscriptions to recurring Stripe prices, each with its subscription license."
1320
+ },
1321
+ "Mrr": {
1322
+ "type": "object",
1323
+ "properties": {
1324
+ "currency": {
1325
+ "type": "string",
1326
+ "example": "USD"
1327
+ },
1328
+ "mrr": {
1329
+ "type": "number",
1330
+ "description": "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.",
1331
+ "example": 1240
1332
+ },
1333
+ "byInterval": {
1334
+ "type": "array",
1335
+ "items": {
1336
+ "type": "object",
1337
+ "properties": {
1338
+ "interval": {
1339
+ "type": "string",
1340
+ "enum": [
1341
+ "day",
1342
+ "week",
1343
+ "month",
1344
+ "year"
1345
+ ]
1346
+ },
1347
+ "intervalCount": {
1348
+ "type": "integer",
1349
+ "example": 1
1350
+ },
1351
+ "subscriptionCount": {
1352
+ "type": "integer",
1353
+ "example": 80
1354
+ },
1355
+ "mrr": {
1356
+ "type": "number",
1357
+ "example": 800
1358
+ }
1359
+ },
1360
+ "required": [
1361
+ "interval",
1362
+ "intervalCount",
1363
+ "subscriptionCount",
1364
+ "mrr"
1365
+ ]
1366
+ },
1367
+ "description": "Ongoing subscriptions and MRR of each billing period, like monthly and yearly, from the highest MRR."
1368
+ },
1369
+ "byPolicy": {
1370
+ "type": "array",
1371
+ "items": {
1372
+ "type": "object",
1373
+ "properties": {
1374
+ "policyId": {
1375
+ "type": "string",
1376
+ "example": "p4Rt8LmQ"
1377
+ },
1378
+ "subscriptionCount": {
1379
+ "type": "integer",
1380
+ "example": 80
1381
+ },
1382
+ "mrr": {
1383
+ "type": "number",
1384
+ "example": 800
1385
+ }
1386
+ },
1387
+ "required": [
1388
+ "policyId",
1389
+ "subscriptionCount",
1390
+ "mrr"
1391
+ ]
1392
+ },
1393
+ "description": "MRR of each policy, from the highest."
1394
+ },
1395
+ "byMonth": {
1396
+ "type": "array",
1397
+ "items": {
1398
+ "type": "number"
1399
+ },
1400
+ "description": "MRR at the end of each month, aligned on `months`, today for this month, at the current prices of the subscriptions.",
1401
+ "example": [
1402
+ 900,
1403
+ 1100,
1404
+ 1240
1405
+ ]
1406
+ }
1407
+ },
1408
+ "required": [
1409
+ "currency",
1410
+ "mrr",
1411
+ "byInterval",
1412
+ "byPolicy",
1413
+ "byMonth"
1414
+ ]
1415
+ },
1213
1416
  "Revenue": {
1214
1417
  "type": "object",
1215
1418
  "properties": {
@@ -1220,22 +1423,32 @@
1220
1423
  },
1221
1424
  "licenseCount": {
1222
1425
  "type": "integer",
1223
- "description": "Number of licenses sold in the currency, free ones included, canceled ones left out.",
1426
+ "description": "Number of licenses sold once in the currency, free ones included, canceled ones and subscription licenses left out.",
1224
1427
  "example": 42
1225
1428
  },
1226
1429
  "total": {
1227
1430
  "type": "number",
1228
- "description": "Sum of the prices of the licenses sold in the currency, in major units, canceled ones left out.",
1431
+ "description": "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`.",
1229
1432
  "example": 2099.58
1230
1433
  },
1434
+ "subscriptionTotal": {
1435
+ "type": "number",
1436
+ "description": "Sum of the payments of the subscription licenses in the currency, before taxes, in major units.",
1437
+ "example": 480
1438
+ },
1439
+ "paymentCount": {
1440
+ "type": "integer",
1441
+ "description": "Number of payments of the subscription licenses in the currency.",
1442
+ "example": 48
1443
+ },
1231
1444
  "canceledLicenseCount": {
1232
1445
  "type": "integer",
1233
- "description": "Number of canceled licenses sold in the currency.",
1446
+ "description": "Number of canceled licenses sold once in the currency.",
1234
1447
  "example": 2
1235
1448
  },
1236
1449
  "canceledTotal": {
1237
1450
  "type": "number",
1238
- "description": "Sum of the prices of the canceled licenses sold in the currency, in major units: revenue lost to cancellations.",
1451
+ "description": "Sum of the prices of the canceled licenses sold once in the currency, in major units: revenue lost to cancellations.",
1239
1452
  "example": 99.98
1240
1453
  },
1241
1454
  "thisMonth": {
@@ -1324,6 +1537,8 @@
1324
1537
  "currency",
1325
1538
  "licenseCount",
1326
1539
  "total",
1540
+ "subscriptionTotal",
1541
+ "paymentCount",
1327
1542
  "canceledLicenseCount",
1328
1543
  "canceledTotal",
1329
1544
  "thisMonth",
@@ -1333,7 +1548,7 @@
1333
1548
  "byMonth",
1334
1549
  "byPolicy"
1335
1550
  ],
1336
- "description": "Revenue of the licenses sold in one currency, each license counting on the day it was created. Licenses without a price are left out, and so are canceled ones, but in `canceledLicenseCount` and `canceledTotal`."
1551
+ "description": "Revenue in one currency: the licenses sold once, each counting on the day it was created, and the payments of the subscription licenses, each counting on the day it was paid, with the license's policy. Licenses without a price are left out, and so are canceled ones, but in `canceledLicenseCount` and `canceledTotal`."
1337
1552
  },
1338
1553
  "PolicyList": {
1339
1554
  "type": "object",
@@ -1994,6 +2209,9 @@
1994
2209
  }
1995
2210
  ]
1996
2211
  },
2212
+ "subscription": {
2213
+ "$ref": "#/components/schemas/LicenseSubscription"
2214
+ },
1997
2215
  "cancellationComment": {
1998
2216
  "type": [
1999
2217
  "string",
@@ -2037,6 +2255,7 @@
2037
2255
  "cancellableUntil",
2038
2256
  "canceledAt",
2039
2257
  "cancellationReason",
2258
+ "subscription",
2040
2259
  "cancellationComment",
2041
2260
  "stripeRefundId",
2042
2261
  "updatedAt"
@@ -2114,6 +2333,80 @@
2114
2333
  "description": "`canceled` when the license was canceled, `expired` when it has expired, `active` when a machine validated its key in the last 90 days, `inactive` otherwise.",
2115
2334
  "example": "active"
2116
2335
  },
2336
+ "LicenseSubscription": {
2337
+ "type": [
2338
+ "object",
2339
+ "null"
2340
+ ],
2341
+ "properties": {
2342
+ "stripeSubscriptionId": {
2343
+ "type": "string",
2344
+ "example": "sub_1MowQVLkdIwHu7ix"
2345
+ },
2346
+ "status": {
2347
+ "type": "string",
2348
+ "description": "Status of the subscription in Stripe: `active`, `trialing`, `past_due` while a failed payment is retried, `canceled`, `unpaid`, `paused`, `incomplete` or `incomplete_expired`.",
2349
+ "example": "active"
2350
+ },
2351
+ "interval": {
2352
+ "type": "string",
2353
+ "enum": [
2354
+ "day",
2355
+ "week",
2356
+ "month",
2357
+ "year"
2358
+ ]
2359
+ },
2360
+ "intervalCount": {
2361
+ "type": "integer",
2362
+ "description": "Number of intervals between payments.",
2363
+ "example": 1
2364
+ },
2365
+ "quantity": {
2366
+ "type": "integer",
2367
+ "description": "Units subscribed, multiplying the policy's machines.",
2368
+ "example": 1
2369
+ },
2370
+ "price": {
2371
+ "allOf": [
2372
+ {
2373
+ "$ref": "#/components/schemas/Price"
2374
+ },
2375
+ {
2376
+ "description": "Price of one unit for one period, before taxes."
2377
+ }
2378
+ ]
2379
+ },
2380
+ "currentPeriodEnd": {
2381
+ "type": "string",
2382
+ "format": "date-time",
2383
+ "description": "End of the paid period, when the subscription renews or ends."
2384
+ },
2385
+ "cancelAtPeriodEnd": {
2386
+ "type": "boolean",
2387
+ "description": "Whether the subscription ends at the end of the period."
2388
+ },
2389
+ "endedAt": {
2390
+ "type": [
2391
+ "string",
2392
+ "null"
2393
+ ],
2394
+ "format": "date-time"
2395
+ }
2396
+ },
2397
+ "required": [
2398
+ "stripeSubscriptionId",
2399
+ "status",
2400
+ "interval",
2401
+ "intervalCount",
2402
+ "quantity",
2403
+ "price",
2404
+ "currentPeriodEnd",
2405
+ "cancelAtPeriodEnd",
2406
+ "endedAt"
2407
+ ],
2408
+ "description": "The Stripe subscription keeping the license valid, `null` when it isn't a subscription license. The license expires when it stops being paid, includes every update, and can't be canceled during a money back guarantee."
2409
+ },
2117
2410
  "CreateLicense": {
2118
2411
  "type": "object",
2119
2412
  "properties": {
@@ -2616,6 +2909,30 @@
2616
2909
  "expiresInSeconds"
2617
2910
  ]
2618
2911
  },
2912
+ "BillingPortalSession": {
2913
+ "type": "object",
2914
+ "properties": {
2915
+ "url": {
2916
+ "type": "string",
2917
+ "description": "Link to the Stripe customer portal, to open right away: it expires shortly.",
2918
+ "example": "https://billing.stripe.com/p/session/test_YWNjdF8x"
2919
+ }
2920
+ },
2921
+ "required": [
2922
+ "url"
2923
+ ]
2924
+ },
2925
+ "CreateBillingPortalSession": {
2926
+ "type": "object",
2927
+ "properties": {
2928
+ "returnUrl": {
2929
+ "type": "string",
2930
+ "format": "uri",
2931
+ "description": "Where the Stripe customer portal links back to: a page of the customer portal, or of one of the product's `returnDomains`. The customer portal of the product by default.",
2932
+ "example": "https://example.com/account"
2933
+ }
2934
+ }
2935
+ },
2619
2936
  "SendPortalLink": {
2620
2937
  "type": "object",
2621
2938
  "properties": {
@@ -2786,6 +3103,7 @@
2786
3103
  "enum": [
2787
3104
  "customer:read",
2788
3105
  "customer:write",
3106
+ "customer:billing",
2789
3107
  "license:read",
2790
3108
  "license:write",
2791
3109
  "license:cancel",
@@ -2822,6 +3140,7 @@
2822
3140
  "enum": [
2823
3141
  "customer:read",
2824
3142
  "customer:write",
3143
+ "customer:billing",
2825
3144
  "license:read",
2826
3145
  "license:write",
2827
3146
  "license:cancel",
@@ -2944,9 +3263,12 @@
2944
3263
  "license.canceled",
2945
3264
  "license.refunded",
2946
3265
  "license.refund_failed",
3266
+ "license.payment_succeeded",
3267
+ "license.payment_failed",
3268
+ "license.subscription_ended",
2947
3269
  "machine.deactivated"
2948
3270
  ],
2949
- "description": "- `policy.created`: `payload` holds the policy's settings.\n- `policy.updated`: `payload.changes` maps each changed field to its previous (`from`) and new (`to`) value. Making a policy the default also updates the previous default one.\n- `license.created`: `payload` holds the license's key, `policyId`, `customerId` and settings. Not linked to the policy.\n- `license.updated`: `payload.changes`, like `policy.updated`.\n- `license.validated`: a machine validated the license key. `payload` holds the machine's `fingerprint`, `name` and `version`, whether the validation created the machine (`machineCreated`) or activated it again (`machineActivated`), the `overriddenMachineId` of the machine it deactivated to take its place, `null` when none, and the `lockedMachineIds` of the machines it locked as it took its place back (see `validateKey`).\n- `license.validation_failed`: validating the license key failed. `payload` holds the error `code` and `message`, and the `fingerprint`, `name`, `platform` and `version` sent, the name and platform being the machine's when none is sent. Linked to the machine when it exists.\n- `license.canceled`: the license was canceled. `payload` holds the cancellation `reason` and `comment`, and whether its Stripe payment is being refunded (`refund`).\n- `license.refunded`: the Stripe payment of a canceled license was refunded. `payload` holds the Stripe `refundId` and the `amount` refunded. Has the `integration` actor.\n- `license.refund_failed`: refunding the Stripe payment of a canceled license failed. `payload` holds the error `message`: refund it from Stripe. Has the `integration` actor.\n- `machine.deactivated`: a machine was deactivated or locked, so it no longer counts as using the license. `payload` holds the machine's `fingerprint` and `name`, the `overriddenByMachineId` of the machine that took its place, `null` when it was deactivated through the API, and whether it was `locked`. Deactivations by validations have the `automation` actor. Linked to the license and the machine.\n\nAn update that changes nothing records no event. Deletions record no events, and customers, products and releases have none.",
3271
+ "description": "- `policy.created`: `payload` holds the policy's settings.\n- `policy.updated`: `payload.changes` maps each changed field to its previous (`from`) and new (`to`) value. Making a policy the default also updates the previous default one.\n- `license.created`: `payload` holds the license's key, `policyId`, `customerId` and settings. Not linked to the policy.\n- `license.updated`: `payload.changes`, like `policy.updated`.\n- `license.validated`: a machine validated the license key. `payload` holds the machine's `fingerprint`, `name` and `version`, whether the validation created the machine (`machineCreated`) or activated it again (`machineActivated`), the `overriddenMachineId` of the machine it deactivated to take its place, `null` when none, and the `lockedMachineIds` of the machines it locked as it took its place back (see `validateKey`).\n- `license.validation_failed`: validating the license key failed. `payload` holds the error `code` and `message`, and the `fingerprint`, `name`, `platform` and `version` sent, the name and platform being the machine's when none is sent. Linked to the machine when it exists.\n- `license.canceled`: the license was canceled. `payload` holds the cancellation `reason` and `comment`, and whether its Stripe payment is being refunded (`refund`).\n- `license.refunded`: the Stripe payment of a canceled license was refunded. `payload` holds the Stripe `refundId` and the `amount` refunded. Has the `integration` actor.\n- `license.refund_failed`: refunding the Stripe payment of a canceled license failed. `payload` holds the error `message`: refund it from Stripe. Has the `integration` actor.\n- `license.payment_succeeded`: a payment of the license's Stripe subscription succeeded, its first one included. `payload` holds the Stripe `invoiceId`, the `amount` paid before taxes and its `currency`, Stripe's `billingReason` (`subscription_create`, `subscription_cycle`, `subscription_update`…) and the `periodStart` and `periodEnd` it pays for. Invoices with nothing to pay, like for a trial, record none. Has the `integration` actor.\n- `license.payment_failed`: a payment of the license's Stripe subscription failed. `payload` holds the Stripe `invoiceId`, the `amount` due and its `currency`, the `attemptCount` and when Stripe tries again (`nextAttemptAt`, `null` when it won't). The license stays valid for the integration's grace days after its period ends. Has the `integration` actor.\n- `license.subscription_ended`: the license's Stripe subscription ended, canceled or no longer paid, so the license expired. `payload` holds the subscription's `status` and Stripe's cancellation `reason`. Has the `integration` actor.\n- `machine.deactivated`: a machine was deactivated or locked, so it no longer counts as using the license. `payload` holds the machine's `fingerprint` and `name`, the `overriddenByMachineId` of the machine that took its place, `null` when it was deactivated through the API, and whether it was `locked`. Deactivations by validations have the `automation` actor. Linked to the license and the machine.\n\nAn update that changes nothing records no event. Deletions record no events, and customers, products and releases have none.",
2950
3272
  "example": "license.validated"
2951
3273
  },
2952
3274
  "EventMachine": {
@@ -3216,13 +3538,19 @@
3216
3538
  "type": "boolean",
3217
3539
  "description": "Whether the key can connect without it, losing what it's for, explained by `reason`.",
3218
3540
  "example": false
3541
+ },
3542
+ "subscriptions": {
3543
+ "type": "boolean",
3544
+ "description": "Whether it's only needed to sell subscriptions: checked once a recurring price is mapped.",
3545
+ "example": false
3219
3546
  }
3220
3547
  },
3221
3548
  "required": [
3222
3549
  "resource",
3223
3550
  "access",
3224
3551
  "reason",
3225
- "optional"
3552
+ "optional",
3553
+ "subscriptions"
3226
3554
  ]
3227
3555
  },
3228
3556
  "Integration": {
@@ -3297,6 +3625,21 @@
3297
3625
  "description": "Whether the API key has the optional Refunds: Write permission, checked when connecting and every day. Without it, canceled licenses aren't refunded: refund their payments from Stripe.",
3298
3626
  "example": true
3299
3627
  },
3628
+ "canManageSubscriptions": {
3629
+ "type": "boolean",
3630
+ "description": "Whether the API key has the optional Subscriptions: Write permission, checked when connecting and every day. Without it, subscription licenses can't be canceled from the app: cancel their subscriptions from Stripe.",
3631
+ "example": true
3632
+ },
3633
+ "canBillingPortal": {
3634
+ "type": "boolean",
3635
+ "description": "Whether the API key has the optional Customer portal: Write permission, checked when connecting and every day. Without it, the license portal doesn't link to the Stripe customer portal.",
3636
+ "example": true
3637
+ },
3638
+ "subscriptionGraceDays": {
3639
+ "type": "integer",
3640
+ "description": "Days a subscription license stays valid after its period ends while its renewal is unpaid, as Stripe retries the payment. 7 by default.",
3641
+ "example": 7
3642
+ },
3300
3643
  "createdAt": {
3301
3644
  "type": "string",
3302
3645
  "format": "date-time"
@@ -3315,6 +3658,9 @@
3315
3658
  "lastEventAt",
3316
3659
  "autoRefund",
3317
3660
  "canRefund",
3661
+ "canManageSubscriptions",
3662
+ "canBillingPortal",
3663
+ "subscriptionGraceDays",
3318
3664
  "createdAt"
3319
3665
  ]
3320
3666
  },
@@ -3362,6 +3708,32 @@
3362
3708
  "price": {
3363
3709
  "$ref": "#/components/schemas/Price"
3364
3710
  },
3711
+ "recurring": {
3712
+ "type": [
3713
+ "object",
3714
+ "null"
3715
+ ],
3716
+ "properties": {
3717
+ "interval": {
3718
+ "type": "string",
3719
+ "enum": [
3720
+ "day",
3721
+ "week",
3722
+ "month",
3723
+ "year"
3724
+ ]
3725
+ },
3726
+ "intervalCount": {
3727
+ "type": "integer",
3728
+ "example": 1
3729
+ }
3730
+ },
3731
+ "required": [
3732
+ "interval",
3733
+ "intervalCount"
3734
+ ],
3735
+ "description": "Billing period of a recurring price, `null` for a one-time price. Subscribing to a recurring price creates one subscription license, valid while it's paid."
3736
+ },
3365
3737
  "status": {
3366
3738
  "type": "string",
3367
3739
  "enum": [
@@ -3391,6 +3763,7 @@
3391
3763
  "stripePriceId",
3392
3764
  "productName",
3393
3765
  "price",
3766
+ "recurring",
3394
3767
  "status",
3395
3768
  "statusReason",
3396
3769
  "createdAt"
@@ -3417,6 +3790,13 @@
3417
3790
  "type": "boolean",
3418
3791
  "description": "Whether canceling a license bought through Stripe refunds its payment. Can only be turned on when the integration's `canRefund` is true: the API key has the Refunds: Write permission.",
3419
3792
  "example": false
3793
+ },
3794
+ "subscriptionGraceDays": {
3795
+ "type": "integer",
3796
+ "minimum": 0,
3797
+ "maximum": 60,
3798
+ "description": "Days a subscription license stays valid after its period ends while its renewal is unpaid, as Stripe retries the payment.",
3799
+ "example": 7
3420
3800
  }
3421
3801
  }
3422
3802
  },
@@ -3445,6 +3825,32 @@
3445
3825
  "price": {
3446
3826
  "$ref": "#/components/schemas/Price"
3447
3827
  },
3828
+ "recurring": {
3829
+ "type": [
3830
+ "object",
3831
+ "null"
3832
+ ],
3833
+ "properties": {
3834
+ "interval": {
3835
+ "type": "string",
3836
+ "enum": [
3837
+ "day",
3838
+ "week",
3839
+ "month",
3840
+ "year"
3841
+ ]
3842
+ },
3843
+ "intervalCount": {
3844
+ "type": "integer",
3845
+ "example": 1
3846
+ }
3847
+ },
3848
+ "required": [
3849
+ "interval",
3850
+ "intervalCount"
3851
+ ],
3852
+ "description": "Billing period of a recurring price, `null` for a one-time price."
3853
+ },
3448
3854
  "mapped": {
3449
3855
  "type": "boolean",
3450
3856
  "description": "Whether the price already creates licenses of a product."
@@ -3456,6 +3862,7 @@
3456
3862
  "productName",
3457
3863
  "nickname",
3458
3864
  "price",
3865
+ "recurring",
3459
3866
  "mapped"
3460
3867
  ]
3461
3868
  },
@@ -3465,7 +3872,7 @@
3465
3872
  "stripePriceId": {
3466
3873
  "type": "string",
3467
3874
  "minLength": 1,
3468
- "description": "Active one-time price of the Stripe account.",
3875
+ "description": "Active one-time or licensed recurring price of the Stripe account.",
3469
3876
  "example": "price_1MoBy5LkdIwHu7ix"
3470
3877
  },
3471
3878
  "policyId": {
@@ -6984,6 +7391,16 @@
6984
7391
  }
6985
7392
  }
6986
7393
  },
7394
+ "409": {
7395
+ "description": "`subscription_managed`: the license is a subscription license, whose `expiresAt`, `price`, `maxVersion` and `cancellableUntil` follow its Stripe subscription",
7396
+ "content": {
7397
+ "application/json": {
7398
+ "schema": {
7399
+ "$ref": "#/components/schemas/Error"
7400
+ }
7401
+ }
7402
+ }
7403
+ },
6987
7404
  "422": {
6988
7405
  "description": "`validation_error`: invalid path, query or body, with the `issues`",
6989
7406
  "content": {
@@ -7204,7 +7621,7 @@
7204
7621
  ],
7205
7622
  "operationId": "cancelLicense",
7206
7623
  "summary": "Cancel a license",
7207
- "description": "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.\n\nCustomers 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.\n\nWhen 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.\n\nRecords a `license.canceled` event, then a `license.refunded` or `license.refund_failed` one once the refund is done.\n\n**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.\n\n**Required role permission**: `license:cancel` when called with a session, granted by the member's role. API keys aren't limited by roles.",
7624
+ "description": "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.\n\nCustomers 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.\n\nWhen 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.\n\nA subscription license isn't refunded: its Stripe subscription is canceled at once, without proration, which needs the integration's `canManageSubscriptions`.\n\nRecords a `license.canceled` event, then a `license.refunded` or `license.refund_failed` one once the refund is done.\n\n**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.\n\n**Required role permission**: `license:cancel` when called with a session, granted by the member's role. API keys aren't limited by roles.",
7208
7625
  "security": [
7209
7626
  {
7210
7627
  "apiKey": []
@@ -7291,7 +7708,7 @@
7291
7708
  }
7292
7709
  },
7293
7710
  "409": {
7294
- "description": "`already_canceled`: the license is already canceled. `not_cancellable`: for tokens, the license has no money back guarantee, or it has ended",
7711
+ "description": "`already_canceled`: the license is already canceled. `not_cancellable`: for tokens, the license has no money back guarantee, or it has ended, as subscription licenses have none. `subscription_managed`: the license is a subscription license, and the Stripe API key lacks the Subscriptions: Write permission to cancel its subscription",
7295
7712
  "content": {
7296
7713
  "application/json": {
7297
7714
  "schema": {
@@ -7928,6 +8345,142 @@
7928
8345
  }
7929
8346
  }
7930
8347
  },
8348
+ "/v1/customers/{id}/billing-portal-sessions": {
8349
+ "post": {
8350
+ "tags": [
8351
+ "Portal"
8352
+ ],
8353
+ "operationId": "createBillingPortalSession",
8354
+ "summary": "Open the Stripe customer portal of a customer",
8355
+ "description": "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.\n\n**Token access**: customer tokens with the `customer:billing` permission (or the matching write one). A customer token reaches its own customer.\n\n**Required role permission**: `portalLink:create` when called with a session, granted by the member's role. API keys aren't limited by roles.",
8356
+ "security": [
8357
+ {
8358
+ "apiKey": []
8359
+ },
8360
+ {
8361
+ "token": [
8362
+ "customer:billing"
8363
+ ]
8364
+ }
8365
+ ],
8366
+ "x-required-permissions": [
8367
+ "portalLink:create"
8368
+ ],
8369
+ "parameters": [
8370
+ {
8371
+ "schema": {
8372
+ "type": "string",
8373
+ "example": "c9Wd3RtE"
8374
+ },
8375
+ "required": true,
8376
+ "name": "id",
8377
+ "in": "path"
8378
+ }
8379
+ ],
8380
+ "requestBody": {
8381
+ "required": false,
8382
+ "content": {
8383
+ "application/json": {
8384
+ "schema": {
8385
+ "$ref": "#/components/schemas/CreateBillingPortalSession"
8386
+ }
8387
+ }
8388
+ }
8389
+ },
8390
+ "responses": {
8391
+ "201": {
8392
+ "description": "Created session",
8393
+ "content": {
8394
+ "application/json": {
8395
+ "schema": {
8396
+ "$ref": "#/components/schemas/BillingPortalSession"
8397
+ }
8398
+ }
8399
+ }
8400
+ },
8401
+ "401": {
8402
+ "description": "`unauthorized`: no credentials. `invalid_api_key`: the API key doesn't exist, was revoked or has expired. `invalid_token`: the token's signature is invalid, it has expired, or the resource it's scoped to was deleted",
8403
+ "content": {
8404
+ "application/json": {
8405
+ "schema": {
8406
+ "$ref": "#/components/schemas/Error"
8407
+ }
8408
+ }
8409
+ }
8410
+ },
8411
+ "402": {
8412
+ "description": "`plan_limit_exceeded`: the organization stayed over its plan's limits after the grace period, its API is blocked until it upgrades. `plan_limit_reached`: creating the resource would go over the plan's limit",
8413
+ "content": {
8414
+ "application/json": {
8415
+ "schema": {
8416
+ "$ref": "#/components/schemas/Error"
8417
+ }
8418
+ }
8419
+ }
8420
+ },
8421
+ "403": {
8422
+ "description": "`token_not_allowed`: the endpoint doesn't accept tokens, or not of this type. `insufficient_scope`: the token lacks the permission. `no_active_organization` or `forbidden`: the session has no organization, or isn't a member of the one requested",
8423
+ "content": {
8424
+ "application/json": {
8425
+ "schema": {
8426
+ "$ref": "#/components/schemas/Error"
8427
+ }
8428
+ }
8429
+ }
8430
+ },
8431
+ "404": {
8432
+ "description": "Customer not found",
8433
+ "content": {
8434
+ "application/json": {
8435
+ "schema": {
8436
+ "$ref": "#/components/schemas/Error"
8437
+ }
8438
+ }
8439
+ }
8440
+ },
8441
+ "409": {
8442
+ "description": "`no_stripe_customer`: the customer didn't pay through the Stripe integration. `billing_portal_unavailable`: the Stripe integration isn't connected, or its API key lacks the Customer portal: Write permission",
8443
+ "content": {
8444
+ "application/json": {
8445
+ "schema": {
8446
+ "$ref": "#/components/schemas/Error"
8447
+ }
8448
+ }
8449
+ }
8450
+ },
8451
+ "422": {
8452
+ "description": "`validation_error`: invalid path, query or body, with the `issues`",
8453
+ "content": {
8454
+ "application/json": {
8455
+ "schema": {
8456
+ "$ref": "#/components/schemas/Error"
8457
+ }
8458
+ }
8459
+ }
8460
+ },
8461
+ "429": {
8462
+ "description": "`rate_limited`: the API key made more than 10 requests in the last second. Wait for the `Retry-After` seconds",
8463
+ "content": {
8464
+ "application/json": {
8465
+ "schema": {
8466
+ "$ref": "#/components/schemas/Error"
8467
+ }
8468
+ }
8469
+ }
8470
+ },
8471
+ "502": {
8472
+ "description": "`provider_unavailable`: Stripe refused or couldn't be reached, like when its customer portal isn't configured",
8473
+ "content": {
8474
+ "application/json": {
8475
+ "schema": {
8476
+ "$ref": "#/components/schemas/Error"
8477
+ }
8478
+ }
8479
+ }
8480
+ }
8481
+ }
8482
+ }
8483
+ },
7931
8484
  "/v1/customers/{id}/portal-links/send": {
7932
8485
  "post": {
7933
8486
  "tags": [