orb-billing 2.1.2 → 2.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 (93) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +29 -0
  3. package/index.d.mts +16 -5
  4. package/index.d.ts +16 -5
  5. package/index.d.ts.map +1 -1
  6. package/index.js +7 -6
  7. package/index.js.map +1 -1
  8. package/index.mjs +7 -6
  9. package/index.mjs.map +1 -1
  10. package/package.json +2 -3
  11. package/resources/coupons/coupons.d.ts +3 -22
  12. package/resources/coupons/coupons.d.ts.map +1 -1
  13. package/resources/coupons/coupons.js.map +1 -1
  14. package/resources/coupons/coupons.mjs.map +1 -1
  15. package/resources/customers/costs.d.ts +4 -4
  16. package/resources/customers/costs.d.ts.map +1 -1
  17. package/resources/customers/costs.js.map +1 -1
  18. package/resources/customers/costs.mjs.map +1 -1
  19. package/resources/customers/credits/credits.d.ts +6 -4
  20. package/resources/customers/credits/credits.d.ts.map +1 -1
  21. package/resources/customers/credits/credits.js.map +1 -1
  22. package/resources/customers/credits/credits.mjs.map +1 -1
  23. package/resources/customers/credits/ledger.d.ts +20 -10
  24. package/resources/customers/credits/ledger.d.ts.map +1 -1
  25. package/resources/customers/credits/ledger.js.map +1 -1
  26. package/resources/customers/credits/ledger.mjs.map +1 -1
  27. package/resources/customers/credits/top-ups.d.ts +38 -8
  28. package/resources/customers/credits/top-ups.d.ts.map +1 -1
  29. package/resources/customers/credits/top-ups.js.map +1 -1
  30. package/resources/customers/credits/top-ups.mjs.map +1 -1
  31. package/resources/customers/usage.d.ts +2 -2
  32. package/resources/customers/usage.d.ts.map +1 -1
  33. package/resources/customers/usage.js.map +1 -1
  34. package/resources/customers/usage.mjs.map +1 -1
  35. package/resources/index.d.ts +3 -3
  36. package/resources/index.d.ts.map +1 -1
  37. package/resources/index.js +6 -6
  38. package/resources/index.js.map +1 -1
  39. package/resources/index.mjs +2 -2
  40. package/resources/index.mjs.map +1 -1
  41. package/resources/invoices.d.ts +2 -0
  42. package/resources/invoices.d.ts.map +1 -1
  43. package/resources/invoices.js.map +1 -1
  44. package/resources/invoices.mjs.map +1 -1
  45. package/resources/plans/plans.d.ts +65 -0
  46. package/resources/plans/plans.d.ts.map +1 -1
  47. package/resources/plans/plans.js.map +1 -1
  48. package/resources/plans/plans.mjs.map +1 -1
  49. package/resources/prices/index.d.ts +1 -1
  50. package/resources/prices/index.d.ts.map +1 -1
  51. package/resources/prices/index.js +3 -3
  52. package/resources/prices/index.js.map +1 -1
  53. package/resources/prices/index.mjs +1 -1
  54. package/resources/prices/index.mjs.map +1 -1
  55. package/resources/prices/prices.d.ts +301 -2
  56. package/resources/prices/prices.d.ts.map +1 -1
  57. package/resources/prices/prices.js +26 -0
  58. package/resources/prices/prices.js.map +1 -1
  59. package/resources/prices/prices.mjs +26 -0
  60. package/resources/prices/prices.mjs.map +1 -1
  61. package/resources/shared.d.ts +5 -0
  62. package/resources/shared.d.ts.map +1 -1
  63. package/resources/subscriptions.d.ts +91 -17
  64. package/resources/subscriptions.d.ts.map +1 -1
  65. package/resources/subscriptions.js +6 -0
  66. package/resources/subscriptions.js.map +1 -1
  67. package/resources/subscriptions.mjs +6 -0
  68. package/resources/subscriptions.mjs.map +1 -1
  69. package/resources/webhooks.d.ts +24 -0
  70. package/resources/webhooks.d.ts.map +1 -0
  71. package/resources/webhooks.js +110 -0
  72. package/resources/webhooks.js.map +1 -0
  73. package/resources/webhooks.mjs +106 -0
  74. package/resources/webhooks.mjs.map +1 -0
  75. package/src/index.ts +20 -7
  76. package/src/resources/coupons/coupons.ts +3 -26
  77. package/src/resources/customers/costs.ts +6 -6
  78. package/src/resources/customers/credits/credits.ts +10 -6
  79. package/src/resources/customers/credits/ledger.ts +24 -12
  80. package/src/resources/customers/credits/top-ups.ts +46 -10
  81. package/src/resources/customers/usage.ts +2 -2
  82. package/src/resources/index.ts +12 -2
  83. package/src/resources/invoices.ts +4 -0
  84. package/src/resources/plans/plans.ts +78 -0
  85. package/src/resources/prices/index.ts +10 -1
  86. package/src/resources/prices/prices.ts +428 -0
  87. package/src/resources/shared.ts +8 -0
  88. package/src/resources/subscriptions.ts +122 -20
  89. package/src/resources/webhooks.ts +142 -0
  90. package/src/version.ts +1 -1
  91. package/version.d.ts +1 -1
  92. package/version.js +1 -1
  93. package/version.mjs +1 -1
@@ -4,6 +4,7 @@ import * as Core from "../core";
4
4
  import { APIResource } from "../resource";
5
5
  import { isRequestOptions } from "../core";
6
6
  import * as SubscriptionsAPI from "./subscriptions";
7
+ import * as Shared from "./shared";
7
8
  import * as CustomersAPI from "./customers/customers";
8
9
  import * as PlansAPI from "./plans/plans";
9
10
  import * as PricesAPI from "./prices/prices";
@@ -414,6 +415,28 @@ export class Subscriptions extends APIResource {
414
415
  return this._client.post('/subscriptions', { body, ...options });
415
416
  }
416
417
 
418
+ /**
419
+ * This endpoint can be used to update the `metadata`, `net terms`,
420
+ * `auto_collection`, `invoicing_threshold`, and `default_invoice_memo` properties
421
+ * on a subscription.
422
+ */
423
+ update(
424
+ subscriptionId: string,
425
+ body?: SubscriptionUpdateParams,
426
+ options?: Core.RequestOptions,
427
+ ): Core.APIPromise<Subscription>;
428
+ update(subscriptionId: string, options?: Core.RequestOptions): Core.APIPromise<Subscription>;
429
+ update(
430
+ subscriptionId: string,
431
+ body: SubscriptionUpdateParams | Core.RequestOptions = {},
432
+ options?: Core.RequestOptions,
433
+ ): Core.APIPromise<Subscription> {
434
+ if (isRequestOptions(body)) {
435
+ return this.update(subscriptionId, {}, body);
436
+ }
437
+ return this._client.put(`/subscriptions/${subscriptionId}`, { body, ...options });
438
+ }
439
+
417
440
  /**
418
441
  * This endpoint returns a list of all subscriptions for an account as a
419
442
  * [paginated](../reference/pagination) list, ordered starting from the most
@@ -1670,7 +1693,7 @@ export namespace SubscriptionUsage {
1670
1693
  export interface GroupedSubscriptionUsage {
1671
1694
  data: Array<GroupedSubscriptionUsage.Data>;
1672
1695
 
1673
- pagination_metadata?: GroupedSubscriptionUsage.PaginationMetadata | null;
1696
+ pagination_metadata?: Shared.PaginationMetadata | null;
1674
1697
  }
1675
1698
 
1676
1699
  export namespace GroupedSubscriptionUsage {
@@ -1705,27 +1728,13 @@ export namespace SubscriptionUsage {
1705
1728
  timeframe_start: string;
1706
1729
  }
1707
1730
  }
1708
-
1709
- export interface PaginationMetadata {
1710
- has_more: boolean;
1711
-
1712
- next_cursor: string | null;
1713
- }
1714
1731
  }
1715
1732
  }
1716
1733
 
1717
1734
  export interface Subscriptions {
1718
1735
  data: Array<Subscription>;
1719
1736
 
1720
- pagination_metadata: Subscriptions.PaginationMetadata;
1721
- }
1722
-
1723
- export namespace Subscriptions {
1724
- export interface PaginationMetadata {
1725
- has_more: boolean;
1726
-
1727
- next_cursor: string | null;
1728
- }
1737
+ pagination_metadata: Shared.PaginationMetadata;
1729
1738
  }
1730
1739
 
1731
1740
  export interface SubscriptionFetchCostsResponse {
@@ -3121,6 +3130,43 @@ export namespace SubscriptionCreateParams {
3121
3130
  }
3122
3131
  }
3123
3132
 
3133
+ export interface SubscriptionUpdateParams {
3134
+ /**
3135
+ * Determines whether issued invoices for this subscription will automatically be
3136
+ * charged with the saved payment method on the due date. This property defaults to
3137
+ * the plan's behavior.
3138
+ */
3139
+ auto_collection?: boolean | null;
3140
+
3141
+ /**
3142
+ * Determines the default memo on this subscription's invoices. Note that if this
3143
+ * is not provided, it is determined by the plan configuration.
3144
+ */
3145
+ default_invoice_memo?: string | null;
3146
+
3147
+ /**
3148
+ * When this subscription's accrued usage reaches this threshold, an invoice will
3149
+ * be issued for the subscription. If not specified, invoices will only be issued
3150
+ * at the end of the billing period.
3151
+ */
3152
+ invoicing_threshold?: string | null;
3153
+
3154
+ /**
3155
+ * User-specified key/value pairs for the resource. Individual keys can be removed
3156
+ * by setting the value to `null`, and the entire metadata mapping can be cleared
3157
+ * by setting `metadata` to `null`.
3158
+ */
3159
+ metadata?: Record<string, string | null> | null;
3160
+
3161
+ /**
3162
+ * Determines the difference between the invoice issue date for subscription
3163
+ * invoices as the date that they are due. A value of `0` here represents that the
3164
+ * invoice is due on issue, whereas a value of `30` represents that the customer
3165
+ * has a month to pay the invoice.
3166
+ */
3167
+ net_terms?: number | null;
3168
+ }
3169
+
3124
3170
  export interface SubscriptionListParams extends PageParams {
3125
3171
  'created_at[gt]'?: string | null;
3126
3172
 
@@ -3255,7 +3301,7 @@ export namespace SubscriptionPriceIntervalsParams {
3255
3301
  * The start date of the price interval. This is the date that the price will start
3256
3302
  * billing on the subscription.
3257
3303
  */
3258
- start_date: (string & {}) | 'start_of_term' | 'end_of_term';
3304
+ start_date: (string & {}) | Shared.BillingCycleRelativeDate;
3259
3305
 
3260
3306
  /**
3261
3307
  * A list of discounts to initialize on the price interval.
@@ -3270,7 +3316,7 @@ export namespace SubscriptionPriceIntervalsParams {
3270
3316
  * The end date of the price interval. This is the date that the price will stop
3271
3317
  * billing on the subscription.
3272
3318
  */
3273
- end_date?: (string & {}) | 'start_of_term' | 'end_of_term' | null;
3319
+ end_date?: (string & {}) | Shared.BillingCycleRelativeDate | null;
3274
3320
 
3275
3321
  /**
3276
3322
  * The external price id of the price to add to the subscription.
@@ -3309,6 +3355,7 @@ export namespace SubscriptionPriceIntervalsParams {
3309
3355
  | Add.NewFloatingBulkPrice
3310
3356
  | Add.NewFloatingThresholdTotalAmountPrice
3311
3357
  | Add.NewFloatingTieredPackagePrice
3358
+ | Add.NewFloatingGroupedTieredPrice
3312
3359
  | Add.NewFloatingTieredWithMinimumPrice
3313
3360
  | Add.NewFloatingPackageWithAllocationPrice
3314
3361
  | Add.NewFloatingTieredPackageWithMinimumPrice
@@ -4184,6 +4231,60 @@ export namespace SubscriptionPriceIntervalsParams {
4184
4231
  invoice_grouping_key?: string | null;
4185
4232
  }
4186
4233
 
4234
+ export interface NewFloatingGroupedTieredPrice {
4235
+ /**
4236
+ * The cadence to bill for this price on.
4237
+ */
4238
+ cadence: 'annual' | 'monthly' | 'quarterly' | 'one_time';
4239
+
4240
+ /**
4241
+ * An ISO 4217 currency string for which this price is billed in.
4242
+ */
4243
+ currency: string;
4244
+
4245
+ grouped_tiered_config: Record<string, unknown>;
4246
+
4247
+ /**
4248
+ * The id of the item the plan will be associated with.
4249
+ */
4250
+ item_id: string;
4251
+
4252
+ model_type: 'grouped_tiered';
4253
+
4254
+ /**
4255
+ * The name of the price.
4256
+ */
4257
+ name: string;
4258
+
4259
+ /**
4260
+ * The id of the billable metric for the price. Only needed if the price is
4261
+ * usage-based.
4262
+ */
4263
+ billable_metric_id?: string | null;
4264
+
4265
+ /**
4266
+ * If the Price represents a fixed cost, the price will be billed in-advance if
4267
+ * this is true, and in-arrears if this is false.
4268
+ */
4269
+ billed_in_advance?: boolean | null;
4270
+
4271
+ /**
4272
+ * An alias for the price.
4273
+ */
4274
+ external_price_id?: string | null;
4275
+
4276
+ /**
4277
+ * If the Price represents a fixed cost, this represents the quantity of units
4278
+ * applied.
4279
+ */
4280
+ fixed_price_quantity?: number | null;
4281
+
4282
+ /**
4283
+ * The property used to group this price on an invoice
4284
+ */
4285
+ invoice_grouping_key?: string | null;
4286
+ }
4287
+
4187
4288
  export interface NewFloatingTieredWithMinimumPrice {
4188
4289
  /**
4189
4290
  * The cadence to bill for this price on.
@@ -4418,7 +4519,7 @@ export namespace SubscriptionPriceIntervalsParams {
4418
4519
  * The updated end date of this price interval. If not specified, the start date
4419
4520
  * will not be updated.
4420
4521
  */
4421
- end_date?: (string & {}) | 'start_of_term' | 'end_of_term' | null;
4522
+ end_date?: (string & {}) | Shared.BillingCycleRelativeDate | null;
4422
4523
 
4423
4524
  /**
4424
4525
  * A list of fixed fee quantity transitions to use for this price interval. Note
@@ -4431,7 +4532,7 @@ export namespace SubscriptionPriceIntervalsParams {
4431
4532
  * The updated start date of this price interval. If not specified, the start date
4432
4533
  * will not be updated.
4433
4534
  */
4434
- start_date?: (string & {}) | 'start_of_term' | 'end_of_term';
4535
+ start_date?: (string & {}) | Shared.BillingCycleRelativeDate;
4435
4536
  }
4436
4537
 
4437
4538
  export namespace Edit {
@@ -5591,6 +5692,7 @@ export namespace Subscriptions {
5591
5692
  export import SubscriptionsPage = SubscriptionsAPI.SubscriptionsPage;
5592
5693
  export import SubscriptionFetchScheduleResponsesPage = SubscriptionsAPI.SubscriptionFetchScheduleResponsesPage;
5593
5694
  export import SubscriptionCreateParams = SubscriptionsAPI.SubscriptionCreateParams;
5695
+ export import SubscriptionUpdateParams = SubscriptionsAPI.SubscriptionUpdateParams;
5594
5696
  export import SubscriptionListParams = SubscriptionsAPI.SubscriptionListParams;
5595
5697
  export import SubscriptionCancelParams = SubscriptionsAPI.SubscriptionCancelParams;
5596
5698
  export import SubscriptionFetchCostsParams = SubscriptionsAPI.SubscriptionFetchCostsParams;
@@ -0,0 +1,142 @@
1
+ // File generated from our OpenAPI spec by Stainless.
2
+
3
+ import { APIResource } from "../resource";
4
+ import { createHmac } from 'crypto';
5
+ import { debug, getRequiredHeader, HeadersLike } from "../core";
6
+
7
+ export class Webhooks extends APIResource {
8
+ /**
9
+ * Validates that the given payload was sent by Orb and parses the payload.
10
+ *
11
+ * An error will be raised if the webhook payload was not sent by Orb.
12
+ */
13
+ unwrap(
14
+ payload: string,
15
+ headers: HeadersLike,
16
+ secret: string | undefined | null = this._client.webhookSecret,
17
+ ): Object {
18
+ this.verifySignature(payload, headers, secret);
19
+ return JSON.parse(payload);
20
+ }
21
+
22
+ private parseSecret(secret: string | null | undefined): Uint8Array {
23
+ if (!secret) {
24
+ throw new Error(
25
+ "The webhook secret must either be set using the env var, ORB_WEBHOOK_SECRET, on the client class, Orb({ webhookSecret: '123' }), or passed to this function",
26
+ );
27
+ }
28
+
29
+ const buf = Buffer.from(secret, 'utf-8');
30
+ if (buf.toString('utf-8') !== secret) {
31
+ throw new Error(`Given secret is not valid`);
32
+ }
33
+
34
+ return new Uint8Array(buf);
35
+ }
36
+
37
+ private signPayload(payload: string, { timestamp, secret }: { timestamp: string; secret: Uint8Array }) {
38
+ const encoder = new TextEncoder();
39
+ const toSign = encoder.encode(`v1:${timestamp}:${payload}`);
40
+
41
+ const hmac = createHmac('sha256', secret);
42
+ hmac.update(toSign);
43
+
44
+ return `v1=${hmac.digest('hex')}`;
45
+ }
46
+
47
+ /** Make an assertion, if not `true`, then throw. */
48
+ private assert(expr: unknown, msg = ''): asserts expr {
49
+ if (!expr) {
50
+ throw new Error(msg);
51
+ }
52
+ }
53
+
54
+ /** Compare to array buffers or data views in a way that timing based attacks
55
+ * cannot gain information about the platform. */
56
+ private timingSafeEqual(
57
+ a: ArrayBufferView | ArrayBufferLike | DataView,
58
+ b: ArrayBufferView | ArrayBufferLike | DataView,
59
+ ): boolean {
60
+ if (a.byteLength !== b.byteLength) {
61
+ return false;
62
+ }
63
+ if (!(a instanceof DataView)) {
64
+ a = new DataView(ArrayBuffer.isView(a) ? a.buffer : a);
65
+ }
66
+ if (!(b instanceof DataView)) {
67
+ b = new DataView(ArrayBuffer.isView(b) ? b.buffer : b);
68
+ }
69
+ this.assert(a instanceof DataView);
70
+ this.assert(b instanceof DataView);
71
+ const length = a.byteLength;
72
+ let out = 0;
73
+ let i = -1;
74
+ while (++i < length) {
75
+ out |= a.getUint8(i) ^ b.getUint8(i);
76
+ }
77
+ return out === 0;
78
+ }
79
+
80
+ /**
81
+ * Validates whether or not the webhook payload was sent by Orb.
82
+ *
83
+ * An error will be raised if the webhook payload was not sent by Orb.
84
+ */
85
+ verifySignature(
86
+ body: string,
87
+ headers: HeadersLike,
88
+ secret: string | undefined | null = this._client.webhookSecret,
89
+ ): void {
90
+ const whsecret = this.parseSecret(secret);
91
+
92
+ const msgTimestamp = getRequiredHeader(headers, 'X-Orb-Timestamp');
93
+ const msgSignature = getRequiredHeader(headers, 'X-Orb-Signature');
94
+
95
+ const nowSeconds = Math.floor(Date.now() / 1000);
96
+ // The timestamp header does not include a timezone (it is UTC by default)
97
+ const timezoneSuffix = msgTimestamp.includes('Z') || msgTimestamp.includes('+') ? '' : 'Z'
98
+ const timestamp = new Date(msgTimestamp + timezoneSuffix);
99
+ const timestampSeconds = Math.floor(timestamp.getTime() / 1000);
100
+ if (isNaN(timestampSeconds)) {
101
+ throw new Error('Invalid timestamp header');
102
+ }
103
+
104
+ const webhookToleranceInSeconds = 5 * 60; // 5 minutes
105
+ if (nowSeconds - timestampSeconds > webhookToleranceInSeconds) {
106
+ throw new Error('Webhook timestamp is too old');
107
+ }
108
+
109
+ if (timestampSeconds > nowSeconds + webhookToleranceInSeconds) {
110
+ console.warn({ timestampSeconds, nowSeconds, webhookToleranceInSeconds });
111
+ throw new Error('Webhook timestamp is too new');
112
+ }
113
+
114
+ if (typeof body !== 'string') {
115
+ throw new Error(
116
+ 'Webhook body must be passed as the raw JSON string sent from the server (do not parse it first).',
117
+ );
118
+ }
119
+
120
+ const computedSignature = this.signPayload(body, { timestamp: msgTimestamp, secret: whsecret });
121
+ const expectedSignature = computedSignature.split('=')[1];
122
+
123
+ const passedSignatures = msgSignature.split(' ');
124
+
125
+ const encoder = new globalThis.TextEncoder();
126
+ for (const versionedSignature of passedSignatures) {
127
+ const [version, signature] = versionedSignature.split('=');
128
+ debug('verifySignature', { version, signature, expectedSignature, computedSignature });
129
+
130
+ if (version !== 'v1') {
131
+ continue;
132
+ }
133
+
134
+ if (this.timingSafeEqual(encoder.encode(signature), encoder.encode(expectedSignature))) {
135
+ // valid!
136
+ return;
137
+ }
138
+ }
139
+
140
+ throw new Error('None of the given webhook signatures match the expected signature');
141
+ }
142
+ }
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const VERSION = '2.1.2'; // x-release-please-version
1
+ export const VERSION = '2.3.0'; // x-release-please-version
package/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "2.1.2";
1
+ export declare const VERSION = "2.3.0";
2
2
  //# sourceMappingURL=version.d.ts.map
package/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
- exports.VERSION = '2.1.2'; // x-release-please-version
4
+ exports.VERSION = '2.3.0'; // x-release-please-version
5
5
  //# sourceMappingURL=version.js.map
package/version.mjs CHANGED
@@ -1,2 +1,2 @@
1
- export const VERSION = '2.1.2'; // x-release-please-version
1
+ export const VERSION = '2.3.0'; // x-release-please-version
2
2
  //# sourceMappingURL=version.mjs.map