@billkit-eu/sdk 0.2.1 → 0.4.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/CHANGELOG.md +66 -0
- package/README.md +68 -1
- package/dist/index.cjs +116 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +234 -20
- package/dist/index.d.ts +234 -20
- package/dist/index.js +116 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +3 -0
- package/src/index.ts +3 -0
- package/src/resources.ts +302 -20
- package/src/version.ts +1 -1
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
BillingPortalSessions,
|
|
13
13
|
CheckoutSessions,
|
|
14
14
|
Coupons,
|
|
15
|
+
CreditNotes,
|
|
15
16
|
Customers,
|
|
16
17
|
Disputes,
|
|
17
18
|
Events,
|
|
@@ -58,6 +59,7 @@ export class BillKit {
|
|
|
58
59
|
readonly coupons: Coupons;
|
|
59
60
|
readonly taxRates: TaxRates;
|
|
60
61
|
readonly invoices: Invoices;
|
|
62
|
+
readonly creditNotes: CreditNotes;
|
|
61
63
|
readonly auditLogs: AuditLogs;
|
|
62
64
|
readonly payments: Payments;
|
|
63
65
|
readonly billingPortalSessions: BillingPortalSessions;
|
|
@@ -81,6 +83,7 @@ export class BillKit {
|
|
|
81
83
|
this.coupons = new Coupons(transport);
|
|
82
84
|
this.taxRates = new TaxRates(transport);
|
|
83
85
|
this.invoices = new Invoices(transport);
|
|
86
|
+
this.creditNotes = new CreditNotes(transport);
|
|
84
87
|
this.auditLogs = new AuditLogs(transport);
|
|
85
88
|
this.payments = new Payments(transport);
|
|
86
89
|
this.billingPortalSessions = new BillingPortalSessions(transport);
|
package/src/index.ts
CHANGED
|
@@ -81,9 +81,11 @@ export type {
|
|
|
81
81
|
CreateTaxRateParams,
|
|
82
82
|
CreateUsageRecordParams,
|
|
83
83
|
CreateWebhookEndpointParams,
|
|
84
|
+
CreditNotesListParams,
|
|
84
85
|
EventsListParams,
|
|
85
86
|
IdempotencyOptions,
|
|
86
87
|
ListParams,
|
|
88
|
+
PriceTier,
|
|
87
89
|
PricesListParams,
|
|
88
90
|
RotateProviderCredentialParams,
|
|
89
91
|
SetPortalBrandingParams,
|
|
@@ -95,6 +97,7 @@ export type {
|
|
|
95
97
|
UpdateWebhookEndpointParams,
|
|
96
98
|
UsageRecordsListParams,
|
|
97
99
|
ValidateCouponParams,
|
|
100
|
+
VoidInvoiceParams,
|
|
98
101
|
} from "./resources.js";
|
|
99
102
|
export { DEFAULT_RETRY_POLICY, type RetryPolicy } from "./retry.js";
|
|
100
103
|
export { VERSION } from "./version.js";
|
package/src/resources.ts
CHANGED
|
@@ -109,6 +109,15 @@ export interface UpdateCustomerParams extends IdempotencyOptions {
|
|
|
109
109
|
metadata?: Record<string, string>;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
/** Query parameters accepted by `GET /v1/customers`. */
|
|
113
|
+
export interface CustomerListParams extends BaseListParams {
|
|
114
|
+
/**
|
|
115
|
+
* `false` for customers who have paid, `true` for abandoned checkouts,
|
|
116
|
+
* omitted for both.
|
|
117
|
+
*/
|
|
118
|
+
provisional?: boolean;
|
|
119
|
+
}
|
|
120
|
+
|
|
112
121
|
/**
|
|
113
122
|
* Body for `POST /v1/customers/{id}/vat_number`. The VAT number is
|
|
114
123
|
* sent through VIES server-side; the response carries
|
|
@@ -138,6 +147,16 @@ export interface CreateProductParams extends IdempotencyOptions {
|
|
|
138
147
|
marketing_features?: string[];
|
|
139
148
|
/** Small string metadata map echoed back on the Product object. */
|
|
140
149
|
metadata?: Record<string, string>;
|
|
150
|
+
/**
|
|
151
|
+
* Let a *buyer* type a coupon code at the embedded checkout for this
|
|
152
|
+
* product. Defaults to `false`. A coupon you apply yourself by passing
|
|
153
|
+
* `coupon_code` when you create a Checkout Session is unaffected — that
|
|
154
|
+
* is you discounting your own sale, and it has never needed this flag.
|
|
155
|
+
*
|
|
156
|
+
* The code is redeemed only once the payment settles, so a shopper who
|
|
157
|
+
* tries a single-use code and abandons the checkout does not use it up.
|
|
158
|
+
*/
|
|
159
|
+
allow_promotion_codes?: boolean;
|
|
141
160
|
}
|
|
142
161
|
|
|
143
162
|
export interface UpdateProductParams extends IdempotencyOptions {
|
|
@@ -147,6 +166,8 @@ export interface UpdateProductParams extends IdempotencyOptions {
|
|
|
147
166
|
metadata?: Record<string, string>;
|
|
148
167
|
/** Set false to stop selling a product without deleting history. */
|
|
149
168
|
active?: boolean;
|
|
169
|
+
/** See {@link CreateProductParams.allow_promotion_codes}. */
|
|
170
|
+
allow_promotion_codes?: boolean;
|
|
150
171
|
}
|
|
151
172
|
|
|
152
173
|
/**
|
|
@@ -159,16 +180,94 @@ export interface UpdatePriceParams extends IdempotencyOptions {
|
|
|
159
180
|
active: boolean;
|
|
160
181
|
}
|
|
161
182
|
|
|
183
|
+
/**
|
|
184
|
+
* One band of a tiered price.
|
|
185
|
+
*
|
|
186
|
+
* `up_to` is inclusive, and the **last band must be `"inf"`** because a
|
|
187
|
+
* bounded top band cannot price the usage above it. Bands must strictly
|
|
188
|
+
* increase.
|
|
189
|
+
*
|
|
190
|
+
* A band names a unit rate (`unit_amount` in whole minor units, or
|
|
191
|
+
* `unit_amount_decimal` for a finer one), a `flat_amount` charged once for
|
|
192
|
+
* reaching the band, or both. Write a free band as `unit_amount: 0` rather
|
|
193
|
+
* than by omitting the rate, so "free" is something the price says instead
|
|
194
|
+
* of something it forgot.
|
|
195
|
+
*/
|
|
196
|
+
export interface PriceTier {
|
|
197
|
+
up_to: number | "inf";
|
|
198
|
+
/** Whole minor units per unit in this band. */
|
|
199
|
+
unit_amount?: number;
|
|
200
|
+
/**
|
|
201
|
+
* A rate finer than one minor unit, **as a string** — see
|
|
202
|
+
* {@link CreatePriceParams.unit_amount_decimal} for why it is never a
|
|
203
|
+
* `number`.
|
|
204
|
+
*/
|
|
205
|
+
unit_amount_decimal?: string;
|
|
206
|
+
/** Charged once when the usage reaches this band. Whole minor units. */
|
|
207
|
+
flat_amount?: number;
|
|
208
|
+
}
|
|
209
|
+
|
|
162
210
|
export interface CreatePriceParams extends IdempotencyOptions {
|
|
163
211
|
/** Existing Product id returned from `client.products.create`. */
|
|
164
212
|
product_id: string;
|
|
165
|
-
|
|
213
|
+
/**
|
|
214
|
+
* Whole minor units per period (licensed) or per unit (metered).
|
|
215
|
+
*
|
|
216
|
+
* Optional because a metered price can be priced by
|
|
217
|
+
* {@link CreatePriceParams.unit_amount_decimal} or by
|
|
218
|
+
* {@link CreatePriceParams.tiers} instead. Exactly one of the three; a
|
|
219
|
+
* price with none of them is refused server-side.
|
|
220
|
+
*/
|
|
221
|
+
amount_cents?: number;
|
|
222
|
+
/**
|
|
223
|
+
* A per-unit rate smaller than one minor unit, in **minor units**, to 12
|
|
224
|
+
* decimal places. `"0.02"` is 0.02 cents, i.e. EUR 0.0002 per unit, which
|
|
225
|
+
* is the canonical per-API-call price and not expressible as an integer.
|
|
226
|
+
* Metered prices only.
|
|
227
|
+
*
|
|
228
|
+
* **It is a `string`, and that is load-bearing.** A JS `number` is an
|
|
229
|
+
* IEEE-754 double and cannot hold 0.0002 exactly, so the rate would be
|
|
230
|
+
* corrupted before it was ever multiplied by a quantity. The type forbids
|
|
231
|
+
* a number at compile time, and the SDK throws a `TypeError` if an
|
|
232
|
+
* untyped JavaScript caller passes one anyway.
|
|
233
|
+
*
|
|
234
|
+
* The period's whole quantity is multiplied by the rate and rounded
|
|
235
|
+
* **once**, at the invoice.
|
|
236
|
+
*/
|
|
237
|
+
unit_amount_decimal?: string;
|
|
238
|
+
/**
|
|
239
|
+
* `"per_unit"` (the default) multiplies one rate by the quantity.
|
|
240
|
+
* `"tiered"` prices by bands and requires
|
|
241
|
+
* {@link CreatePriceParams.tiers} and
|
|
242
|
+
* {@link CreatePriceParams.tiers_mode}. Metered prices only.
|
|
243
|
+
*/
|
|
244
|
+
billing_scheme?: "per_unit" | "tiered";
|
|
245
|
+
/**
|
|
246
|
+
* How a tier table is read, and there is **no default** because the same
|
|
247
|
+
* table means two different bills. `"graduated"` prices the units inside
|
|
248
|
+
* each band; `"volume"` lets the period total pick one band which then
|
|
249
|
+
* prices every unit. 1,500 units against "first 1,000 at EUR 0.01, then
|
|
250
|
+
* EUR 0.005" is EUR 12.50 graduated and EUR 7.50 by volume.
|
|
251
|
+
*/
|
|
252
|
+
tiers_mode?: "graduated" | "volume";
|
|
253
|
+
/** The band table. Required when `billing_scheme` is `"tiered"`, refused otherwise. */
|
|
254
|
+
tiers?: PriceTier[];
|
|
166
255
|
currency: string;
|
|
167
256
|
interval: "month" | "year" | (string & {});
|
|
168
257
|
metadata?: Record<string, string>;
|
|
169
258
|
trial_days?: number;
|
|
170
259
|
trial_verification_cents?: number;
|
|
171
|
-
payment_methods?: Array<"creditcard" | "directdebit" | (string & {})>;
|
|
260
|
+
payment_methods?: Array<"creditcard" | "directdebit" | "ideal" | "applepay" | (string & {})>;
|
|
261
|
+
/**
|
|
262
|
+
* What a cancellation refunds without being asked. `"none"` (the default)
|
|
263
|
+
* nothing; `"full"` the whole last charge; `"prorated"` the unused part
|
|
264
|
+
* of the current period. Both non-none modes also end access
|
|
265
|
+
* immediately, and both stay bounded by the refund window below.
|
|
266
|
+
*
|
|
267
|
+
* Metered prices must leave this at `"none"`: ending access mid-period
|
|
268
|
+
* would strand usage that has not been billed yet.
|
|
269
|
+
*/
|
|
270
|
+
refund_on_cancel?: "none" | "full" | "prorated";
|
|
172
271
|
/**
|
|
173
272
|
* Per-Price refund-window override (`POST /v1/prices`). `undefined`
|
|
174
273
|
* inherits the default policy table (7d / 30d initial, 3d renewal);
|
|
@@ -189,12 +288,15 @@ export interface CreatePriceParams extends IdempotencyOptions {
|
|
|
189
288
|
tax_behavior?: "inclusive" | "exclusive" | "unspecified";
|
|
190
289
|
/**
|
|
191
290
|
* `"licensed"` (the default when omitted) bills `amount_cents` per
|
|
192
|
-
* period regardless of consumption. `"metered"` bills
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
291
|
+
* period regardless of consumption. `"metered"` bills **per reported
|
|
292
|
+
* unit**: post consumption with `subscriptions.createUsageRecord`, and
|
|
293
|
+
* at each period close BillKit invoices the period's total and charges
|
|
294
|
+
* the stored mandate.
|
|
295
|
+
*
|
|
296
|
+
* A metered unit is priced by `amount_cents`, by `unit_amount_decimal`,
|
|
297
|
+
* or by `tiers` — exactly one. Metered prices must be
|
|
298
|
+
* `interval: "month"`, cannot have `trial_days`, and cannot set
|
|
299
|
+
* `refund_on_cancel`.
|
|
198
300
|
*/
|
|
199
301
|
usage_type?: "licensed" | "metered";
|
|
200
302
|
}
|
|
@@ -213,6 +315,22 @@ export interface CreateUsageRecordParams extends IdempotencyOptions {
|
|
|
213
315
|
* the record must land in the period the usage occurred.
|
|
214
316
|
*/
|
|
215
317
|
occurred_at?: number;
|
|
318
|
+
/**
|
|
319
|
+
* Your own id for the event being metered, unique within this
|
|
320
|
+
* subscription. This is the dedupe an `Idempotency-Key` cannot do.
|
|
321
|
+
*
|
|
322
|
+
* The key covers a retry of *one HTTP request*, including the SDK's own
|
|
323
|
+
* internal retries. `identifier` covers a retry of *your* call — a job
|
|
324
|
+
* runner replaying a task, a queue delivering twice, your code
|
|
325
|
+
* re-invoking after its own timeout — which arrives at the API as a
|
|
326
|
+
* genuinely new request with a new key. A second report of the same
|
|
327
|
+
* identifier returns the first record unchanged instead of billing
|
|
328
|
+
* twice.
|
|
329
|
+
*
|
|
330
|
+
* If your reporting pipeline is at-least-once, this is the one that
|
|
331
|
+
* matters.
|
|
332
|
+
*/
|
|
333
|
+
identifier?: string;
|
|
216
334
|
/** Small string metadata map echoed back on the record. */
|
|
217
335
|
metadata?: Record<string, string>;
|
|
218
336
|
}
|
|
@@ -254,7 +372,7 @@ export interface CreateCheckoutSessionParams extends IdempotencyOptions {
|
|
|
254
372
|
* the customer's available methods; when set, must be in the price's
|
|
255
373
|
* `payment_methods` allowlist.
|
|
256
374
|
*/
|
|
257
|
-
method?: "creditcard" | "directdebit" | (string & {});
|
|
375
|
+
method?: "creditcard" | "directdebit" | "ideal" | "applepay" | (string & {});
|
|
258
376
|
/** Optional coupon code applied at checkout; atomically claimed. */
|
|
259
377
|
coupon_code?: string;
|
|
260
378
|
/**
|
|
@@ -321,7 +439,14 @@ export interface CreateOneShotPaymentParams extends IdempotencyOptions {
|
|
|
321
439
|
* *request* type the server validates, so an SDK that lags a newly-added
|
|
322
440
|
* method should not be the thing that blocks the call.
|
|
323
441
|
*/
|
|
324
|
-
method:
|
|
442
|
+
method:
|
|
443
|
+
| "creditcard"
|
|
444
|
+
| "directdebit"
|
|
445
|
+
| "ideal"
|
|
446
|
+
| "bancontact"
|
|
447
|
+
| "eps"
|
|
448
|
+
| "applepay"
|
|
449
|
+
| (string & {});
|
|
325
450
|
/** Where Mollie returns the payer after the hosted checkout. */
|
|
326
451
|
success_url: string;
|
|
327
452
|
/** Optional page for an abandoned/cancelled payment. */
|
|
@@ -441,6 +566,23 @@ export interface AuditLogsListParams extends BaseListParams {
|
|
|
441
566
|
actor_id?: string;
|
|
442
567
|
}
|
|
443
568
|
|
|
569
|
+
/**
|
|
570
|
+
* `creditNotes.list` params.
|
|
571
|
+
*
|
|
572
|
+
* `invoice_id` answers "was this sale credited, and by how much", which is
|
|
573
|
+
* the question when reconciling one invoice; `customer_id` answers it for
|
|
574
|
+
* everything credited back to one buyer.
|
|
575
|
+
*/
|
|
576
|
+
export interface CreditNotesListParams extends BaseListParams {
|
|
577
|
+
invoice_id?: string;
|
|
578
|
+
customer_id?: string;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/** `invoices.void` params. `reason` is recorded on the audit row only. */
|
|
582
|
+
export interface VoidInvoiceParams extends IdempotencyOptions {
|
|
583
|
+
reason?: string;
|
|
584
|
+
}
|
|
585
|
+
|
|
444
586
|
export interface CreateBillingPortalSessionParams extends IdempotencyOptions {
|
|
445
587
|
subscription_id: string;
|
|
446
588
|
return_url: string;
|
|
@@ -468,6 +610,40 @@ function splitIdempotency<P extends IdempotencyOptions>(
|
|
|
468
610
|
return { body: dropUndefined(rest as Record<string, unknown>), idempotencyKey };
|
|
469
611
|
}
|
|
470
612
|
|
|
613
|
+
/**
|
|
614
|
+
* Refuse a sub-minor-unit rate that arrived as a `number`.
|
|
615
|
+
*
|
|
616
|
+
* The type already forbids it, so this exists for the callers the type
|
|
617
|
+
* system cannot reach: plain JavaScript, a value that came through `any`,
|
|
618
|
+
* a body parsed from JSON. A double cannot hold 0.0002 exactly, so
|
|
619
|
+
* accepting one would work for the rates that happen to round-trip and
|
|
620
|
+
* silently mis-price the ones that do not — the worst of the three
|
|
621
|
+
* available behaviours, and the reason the field is a string in the first
|
|
622
|
+
* place.
|
|
623
|
+
*/
|
|
624
|
+
function assertDecimalRateIsString(value: unknown, field: string): void {
|
|
625
|
+
if (value === undefined || value === null || typeof value === "string") return;
|
|
626
|
+
throw new TypeError(
|
|
627
|
+
`${field} must be a string, not a ${typeof value}. A JavaScript number cannot ` +
|
|
628
|
+
"hold a rate like 0.0002 exactly, so it would be corrupted before it was ever " +
|
|
629
|
+
`multiplied by a quantity. Pass it as a string: "${String(value)}".`,
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/** Same check at the price level and inside every band of a tier table. */
|
|
634
|
+
function assertPriceRatesAreStrings(params: CreatePriceParams): CreatePriceParams {
|
|
635
|
+
assertDecimalRateIsString(params.unit_amount_decimal, "unit_amount_decimal");
|
|
636
|
+
// Inside a tier is where a rate is most likely to be typed as a bare
|
|
637
|
+
// literal, so the guard has to reach in there too.
|
|
638
|
+
(params.tiers ?? []).forEach((tier, index) => {
|
|
639
|
+
assertDecimalRateIsString(
|
|
640
|
+
(tier as PriceTier | undefined)?.unit_amount_decimal,
|
|
641
|
+
`tiers[${index}].unit_amount_decimal`,
|
|
642
|
+
);
|
|
643
|
+
});
|
|
644
|
+
return params;
|
|
645
|
+
}
|
|
646
|
+
|
|
471
647
|
/**
|
|
472
648
|
* Shared transport wrapper. Resources subclass this so each method
|
|
473
649
|
* reads as a single line, "verb to path with params", instead of
|
|
@@ -550,7 +726,17 @@ export class Customers extends BaseResource {
|
|
|
550
726
|
return this.del<T>(`/v1/customers/${id}`, params);
|
|
551
727
|
}
|
|
552
728
|
|
|
553
|
-
|
|
729
|
+
/**
|
|
730
|
+
* List customers, newest first.
|
|
731
|
+
*
|
|
732
|
+
* `provisional` filters on whether the customer ever completed a
|
|
733
|
+
* payment. A checkout that captures an email commits its Customer
|
|
734
|
+
* before the charge, so a checkout nobody finished leaves a row behind:
|
|
735
|
+
* pass `false` for real customers only, `true` for the abandoned ones
|
|
736
|
+
* (the cart-recovery worklist), or omit for both. Abandoned rows are
|
|
737
|
+
* swept after the tenant's retention window.
|
|
738
|
+
*/
|
|
739
|
+
list<T = unknown>(params: CustomerListParams = {}): Promise<ListResponseEnvelope<T>> {
|
|
554
740
|
return this.get<ListResponseEnvelope<T>>("/v1/customers", params);
|
|
555
741
|
}
|
|
556
742
|
|
|
@@ -615,9 +801,23 @@ export class Products extends BaseResource {
|
|
|
615
801
|
}
|
|
616
802
|
|
|
617
803
|
export class Prices extends BaseResource {
|
|
618
|
-
/**
|
|
619
|
-
|
|
620
|
-
|
|
804
|
+
/**
|
|
805
|
+
* Create immutable billing terms for an existing Product.
|
|
806
|
+
*
|
|
807
|
+
* A licensed price sends `amount_cents`. A metered price sends one of
|
|
808
|
+
* `amount_cents`, `unit_amount_decimal` (a rate finer than one minor
|
|
809
|
+
* unit, as a string) or `billing_scheme: "tiered"` with `tiers` and
|
|
810
|
+
* `tiers_mode`. Throws `TypeError` before any HTTP call if a decimal
|
|
811
|
+
* rate arrives as a number — see
|
|
812
|
+
* {@link CreatePriceParams.unit_amount_decimal}.
|
|
813
|
+
*/
|
|
814
|
+
// `async` on purpose. The rate guard throws, and a synchronous throw out
|
|
815
|
+
// of a method typed `Promise<T>` escapes `.catch()` entirely — the caller
|
|
816
|
+
// would have to wrap the call site in try/catch as well, which nobody
|
|
817
|
+
// does for a promise-returning API. Marking it async turns the throw into
|
|
818
|
+
// a rejection, so one error path handles both.
|
|
819
|
+
async create<T = unknown>(params: CreatePriceParams): Promise<T> {
|
|
820
|
+
return this.post<T, CreatePriceParams>("/v1/prices", assertPriceRatesAreStrings(params));
|
|
621
821
|
}
|
|
622
822
|
|
|
623
823
|
retrieve<T = unknown>(id: string): Promise<T> {
|
|
@@ -783,13 +983,16 @@ export class Subscriptions extends BaseResource {
|
|
|
783
983
|
*
|
|
784
984
|
* Only valid when the subscription's price is `usage_type:
|
|
785
985
|
* "metered"`; a licensed subscription is rejected with `400
|
|
786
|
-
* parameter_invalid`. Records accumulate until the
|
|
787
|
-
* rolls them
|
|
788
|
-
* `
|
|
986
|
+
* parameter_invalid`. Records accumulate until the next period close
|
|
987
|
+
* rolls them into one invoice line; the record's `invoice_id` stays
|
|
988
|
+
* `null` until then. Records are immutable once written — they are the
|
|
989
|
+
* audit trail behind that line — so there is no update or delete.
|
|
789
990
|
*
|
|
790
|
-
*
|
|
791
|
-
*
|
|
792
|
-
*
|
|
991
|
+
* Two dedupe mechanisms, covering different failures. The
|
|
992
|
+
* `Idempotency-Key` the SDK sends covers a retry of this HTTP request,
|
|
993
|
+
* including its own internal retries. `params.identifier` covers a
|
|
994
|
+
* retry of *your* call, which arrives as a new request with a new key.
|
|
995
|
+
* See {@link CreateUsageRecordParams.identifier}.
|
|
793
996
|
*/
|
|
794
997
|
createUsageRecord<T = unknown>(id: string, params: CreateUsageRecordParams): Promise<T> {
|
|
795
998
|
return this.post<T, CreateUsageRecordParams>(`/v1/subscriptions/${id}/usage_records`, params);
|
|
@@ -819,6 +1022,28 @@ export class Subscriptions extends BaseResource {
|
|
|
819
1022
|
filters: { invoice_id: options.invoice_id },
|
|
820
1023
|
});
|
|
821
1024
|
}
|
|
1025
|
+
|
|
1026
|
+
/**
|
|
1027
|
+
* Price the pending usage, before the period close bills it.
|
|
1028
|
+
*
|
|
1029
|
+
* `listUsageRecords({ invoice_id: "pending" })` gives the quantity; this
|
|
1030
|
+
* gives the money. `net_cents` / `tax_cents` / `gross_cents` are
|
|
1031
|
+
* computed through the same rate or tier table and the same VAT
|
|
1032
|
+
* resolution the close itself uses, so it is a forecast of the real
|
|
1033
|
+
* invoice rather than an estimate.
|
|
1034
|
+
*
|
|
1035
|
+
* **Read `will_charge` before promising a customer an amount.** A period
|
|
1036
|
+
* whose total is under `minimum_charge_cents` (EUR 1.00) is not charged,
|
|
1037
|
+
* because the payment provider would refuse it. The usage is not lost:
|
|
1038
|
+
* it stays pending and rolls into the next period, which is then billed
|
|
1039
|
+
* for both.
|
|
1040
|
+
*
|
|
1041
|
+
* `open_invoice_id` names an earlier cycle that is invoiced and still
|
|
1042
|
+
* unsettled; while one is open, this period cannot be charged.
|
|
1043
|
+
*/
|
|
1044
|
+
retrieveUsageSummary<T = unknown>(id: string): Promise<T> {
|
|
1045
|
+
return this.get<T>(`/v1/subscriptions/${id}/usage_summary`);
|
|
1046
|
+
}
|
|
822
1047
|
}
|
|
823
1048
|
|
|
824
1049
|
export class Refunds extends BaseResource {
|
|
@@ -1146,6 +1371,63 @@ export class Invoices extends BaseResource {
|
|
|
1146
1371
|
iter<T = unknown>(options: { pageSize?: number } = {}): AsyncIterableIterator<T> {
|
|
1147
1372
|
return paginate<T>((p) => this.get("/v1/invoices", p), { pageSize: options.pageSize });
|
|
1148
1373
|
}
|
|
1374
|
+
|
|
1375
|
+
/**
|
|
1376
|
+
* Void an invoice: state that the sale was never owed.
|
|
1377
|
+
*
|
|
1378
|
+
* The invoice keeps its number and stays readable — a gapless series
|
|
1379
|
+
* cannot lose a row — and stops being a receivable. Use it for an
|
|
1380
|
+
* invoice that should not have been issued.
|
|
1381
|
+
*
|
|
1382
|
+
* A **paid** invoice is refused with a `ConflictError` whose `code` is
|
|
1383
|
+
* `"invoice_not_voidable"`. That is deliberate rather than a
|
|
1384
|
+
* limitation: once the money has moved, "never owed" is false, and the
|
|
1385
|
+
* document that reverses a real sale is a credit note — refund the
|
|
1386
|
+
* payment and one is issued when the refund settles.
|
|
1387
|
+
*
|
|
1388
|
+
* Idempotent: re-voiding an already-void invoice returns it unchanged.
|
|
1389
|
+
*/
|
|
1390
|
+
void<T = unknown>(id: string, params: VoidInvoiceParams = {}): Promise<T> {
|
|
1391
|
+
return this.post<T, VoidInvoiceParams>(`/v1/invoices/${id}/void`, params);
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
/**
|
|
1396
|
+
* Read-only access to credit notes — the documents that reverse an
|
|
1397
|
+
* issued invoice.
|
|
1398
|
+
*
|
|
1399
|
+
* There is no create: a credit note is issued for you when a refund
|
|
1400
|
+
* settles, never on request, so that a numbered legal record is only
|
|
1401
|
+
* minted once the money has actually moved. A refund that is still
|
|
1402
|
+
* pending, one that fails, and a refund of a one-off charge that was
|
|
1403
|
+
* never invoiced all produce none.
|
|
1404
|
+
*/
|
|
1405
|
+
export class CreditNotes extends BaseResource {
|
|
1406
|
+
retrieve<T = unknown>(id: string): Promise<T> {
|
|
1407
|
+
return this.get<T>(`/v1/credit_notes/${id}`);
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
/**
|
|
1411
|
+
* Download the rendered credit note PDF as raw bytes. Same storage
|
|
1412
|
+
* split as {@link Invoices.retrievePdf}: bytes inline or a followed
|
|
1413
|
+
* `302`, and `501 rendering_pending` on a deployment with no renderer.
|
|
1414
|
+
*/
|
|
1415
|
+
retrievePdf(id: string): Promise<ArrayBuffer> {
|
|
1416
|
+
return this.t.requestBinary({ method: "GET", path: `/v1/credit_notes/${id}/pdf` });
|
|
1417
|
+
}
|
|
1418
|
+
|
|
1419
|
+
list<T = unknown>(params: CreditNotesListParams = {}): Promise<ListResponseEnvelope<T>> {
|
|
1420
|
+
return this.get<ListResponseEnvelope<T>>("/v1/credit_notes", params);
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
iter<T = unknown>(
|
|
1424
|
+
options: { pageSize?: number; invoice_id?: string; customer_id?: string } = {},
|
|
1425
|
+
): AsyncIterableIterator<T> {
|
|
1426
|
+
return paginate<T>((p) => this.get("/v1/credit_notes", p), {
|
|
1427
|
+
pageSize: options.pageSize,
|
|
1428
|
+
filters: { invoice_id: options.invoice_id, customer_id: options.customer_id },
|
|
1429
|
+
});
|
|
1430
|
+
}
|
|
1149
1431
|
}
|
|
1150
1432
|
|
|
1151
1433
|
/**
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = "0.
|
|
1
|
+
export const VERSION = "0.4.0";
|