@billkit-eu/sdk 0.2.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.
package/dist/index.js CHANGED
@@ -35,6 +35,22 @@ function splitIdempotency(params) {
35
35
  const { idempotencyKey, ...rest } = params;
36
36
  return { body: dropUndefined(rest), idempotencyKey };
37
37
  }
38
+ function assertDecimalRateIsString(value, field) {
39
+ if (value === void 0 || value === null || typeof value === "string") return;
40
+ throw new TypeError(
41
+ `${field} must be a string, not a ${typeof value}. A JavaScript number cannot hold a rate like 0.0002 exactly, so it would be corrupted before it was ever multiplied by a quantity. Pass it as a string: "${String(value)}".`
42
+ );
43
+ }
44
+ function assertPriceRatesAreStrings(params) {
45
+ assertDecimalRateIsString(params.unit_amount_decimal, "unit_amount_decimal");
46
+ (params.tiers ?? []).forEach((tier, index) => {
47
+ assertDecimalRateIsString(
48
+ tier?.unit_amount_decimal,
49
+ `tiers[${index}].unit_amount_decimal`
50
+ );
51
+ });
52
+ return params;
53
+ }
38
54
  var BaseResource = class {
39
55
  constructor(t) {
40
56
  this.t = t;
@@ -98,6 +114,16 @@ var Customers = class extends BaseResource {
98
114
  delete(id, params = {}) {
99
115
  return this.del(`/v1/customers/${id}`, params);
100
116
  }
117
+ /**
118
+ * List customers, newest first.
119
+ *
120
+ * `provisional` filters on whether the customer ever completed a
121
+ * payment. A checkout that captures an email commits its Customer
122
+ * before the charge, so a checkout nobody finished leaves a row behind:
123
+ * pass `false` for real customers only, `true` for the abandoned ones
124
+ * (the cart-recovery worklist), or omit for both. Abandoned rows are
125
+ * swept after the tenant's retention window.
126
+ */
101
127
  list(params = {}) {
102
128
  return this.get("/v1/customers", params);
103
129
  }
@@ -154,9 +180,23 @@ var Products = class extends BaseResource {
154
180
  }
155
181
  };
156
182
  var Prices = class extends BaseResource {
157
- /** Create immutable billing terms for an existing Product. */
158
- create(params) {
159
- return this.post("/v1/prices", params);
183
+ /**
184
+ * Create immutable billing terms for an existing Product.
185
+ *
186
+ * A licensed price sends `amount_cents`. A metered price sends one of
187
+ * `amount_cents`, `unit_amount_decimal` (a rate finer than one minor
188
+ * unit, as a string) or `billing_scheme: "tiered"` with `tiers` and
189
+ * `tiers_mode`. Throws `TypeError` before any HTTP call if a decimal
190
+ * rate arrives as a number — see
191
+ * {@link CreatePriceParams.unit_amount_decimal}.
192
+ */
193
+ // `async` on purpose. The rate guard throws, and a synchronous throw out
194
+ // of a method typed `Promise<T>` escapes `.catch()` entirely — the caller
195
+ // would have to wrap the call site in try/catch as well, which nobody
196
+ // does for a promise-returning API. Marking it async turns the throw into
197
+ // a rejection, so one error path handles both.
198
+ async create(params) {
199
+ return this.post("/v1/prices", assertPriceRatesAreStrings(params));
160
200
  }
161
201
  retrieve(id) {
162
202
  return this.get(`/v1/prices/${id}`);
@@ -277,13 +317,16 @@ var Subscriptions = class extends BaseResource {
277
317
  *
278
318
  * Only valid when the subscription's price is `usage_type:
279
319
  * "metered"`; a licensed subscription is rejected with `400
280
- * parameter_invalid`. Records accumulate until the renewal invoice
281
- * rolls them up (`amount_cents × sum(quantity)`); the record's
282
- * `invoice_id` stays `null` until then.
320
+ * parameter_invalid`. Records accumulate until the next period close
321
+ * rolls them into one invoice line; the record's `invoice_id` stays
322
+ * `null` until then. Records are immutable once written — they are the
323
+ * audit trail behind that line — so there is no update or delete.
283
324
  *
284
- * Supports `Idempotency-Key` replay: retrying with the same key
285
- * returns the same record instead of double-counting the usage,
286
- * which is what makes at-least-once reporting pipelines safe.
325
+ * Two dedupe mechanisms, covering different failures. The
326
+ * `Idempotency-Key` the SDK sends covers a retry of this HTTP request,
327
+ * including its own internal retries. `params.identifier` covers a
328
+ * retry of *your* call, which arrives as a new request with a new key.
329
+ * See {@link CreateUsageRecordParams.identifier}.
287
330
  */
288
331
  createUsageRecord(id, params) {
289
332
  return this.post(`/v1/subscriptions/${id}/usage_records`, params);
@@ -305,6 +348,27 @@ var Subscriptions = class extends BaseResource {
305
348
  filters: { invoice_id: options.invoice_id }
306
349
  });
307
350
  }
351
+ /**
352
+ * Price the pending usage, before the period close bills it.
353
+ *
354
+ * `listUsageRecords({ invoice_id: "pending" })` gives the quantity; this
355
+ * gives the money. `net_cents` / `tax_cents` / `gross_cents` are
356
+ * computed through the same rate or tier table and the same VAT
357
+ * resolution the close itself uses, so it is a forecast of the real
358
+ * invoice rather than an estimate.
359
+ *
360
+ * **Read `will_charge` before promising a customer an amount.** A period
361
+ * whose total is under `minimum_charge_cents` (EUR 1.00) is not charged,
362
+ * because the payment provider would refuse it. The usage is not lost:
363
+ * it stays pending and rolls into the next period, which is then billed
364
+ * for both.
365
+ *
366
+ * `open_invoice_id` names an earlier cycle that is invoiced and still
367
+ * unsettled; while one is open, this period cannot be charged.
368
+ */
369
+ retrieveUsageSummary(id) {
370
+ return this.get(`/v1/subscriptions/${id}/usage_summary`);
371
+ }
308
372
  };
309
373
  var Refunds = class extends BaseResource {
310
374
  create(params) {
@@ -731,7 +795,7 @@ function sleep(ms) {
731
795
  }
732
796
 
733
797
  // src/version.ts
734
- var VERSION = "0.2.1";
798
+ var VERSION = "0.3.0";
735
799
 
736
800
  // src/transport.ts
737
801
  var DEFAULT_BASE_URL = "https://api.billkit.eu";