@fleetless/contracts 6.2.0 → 6.3.0-next.1

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 (31) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/artifacts/openapi.json +4322 -1887
  3. package/artifacts/routes.json +326 -2
  4. package/artifacts/schema/billing-address.schema.json +49 -0
  5. package/artifacts/schema/billing-cancel-request.schema.json +12 -0
  6. package/artifacts/schema/billing-change-request.schema.json +60 -0
  7. package/artifacts/schema/billing-change-response.schema.json +765 -0
  8. package/artifacts/schema/billing-details-update.schema.json +25 -0
  9. package/artifacts/schema/billing-details.schema.json +176 -0
  10. package/artifacts/schema/billing-invoice.schema.json +76 -0
  11. package/artifacts/schema/billing-view.schema.json +671 -0
  12. package/artifacts/schema/checkout-request.schema.json +252 -0
  13. package/artifacts/schema/checkout-response.schema.json +22 -0
  14. package/artifacts/schema/checkout-status.schema.json +49 -0
  15. package/artifacts/schema/payment-method-change-request.schema.json +19 -0
  16. package/artifacts/schema/payment-method.schema.json +80 -0
  17. package/artifacts/schema/payment-provider-unavailable-details.schema.json +29 -0
  18. package/artifacts/schema/vat-id-check-request.schema.json +22 -0
  19. package/artifacts/schema/vat-id-check-response.schema.json +36 -0
  20. package/dist/billing.d.ts +778 -0
  21. package/dist/billing.js +441 -0
  22. package/dist/errors.d.ts +17 -5
  23. package/dist/errors.js +31 -0
  24. package/dist/index.d.ts +4 -2
  25. package/dist/index.js +5 -1
  26. package/dist/plans.d.ts +9 -9
  27. package/dist/realtime.d.ts +2 -2
  28. package/dist/rest.d.ts +3 -3
  29. package/dist/routes.d.ts +1 -1
  30. package/dist/routes.js +181 -4
  31. package/package.json +1 -1
@@ -0,0 +1,778 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ import { z } from 'zod';
3
+ import { type AddonKey, type OrgAddons, type PlanCurrency, type PlanId } from './plans.js';
4
+ /**
5
+ * Countries, VAT and the money math for billing through Mollie
6
+ * (fleetless/fleetless#104).
7
+ *
8
+ * Every price here reads from `plans.ts`'s `PLANS` / `ADDONS` catalogue,
9
+ * never a cent amount of its own, so a price change in one place is a price
10
+ * change everywhere. Money is integer cents throughout; the one rounding a
11
+ * proration or a VAT amount is allowed is `Math.round`, applied exactly
12
+ * once (`prorateCents`, `vatCents`, and `changeNetCents`'s single
13
+ * proration).
14
+ */
15
+ /** ISO 3166-1 alpha-2, upper case. Greece is `GR` here; VIES calls it `EL`. */
16
+ export declare const countryCode: z.ZodString;
17
+ /** The 27 EU member states, as the billing country. Greece is `GR`. */
18
+ export declare const EU_COUNTRIES: readonly ["AT", "BE", "BG", "CY", "CZ", "DE", "DK", "EE", "ES", "FI", "FR", "GR", "HR", "HU", "IE", "IT", "LT", "LU", "LV", "MT", "NL", "PL", "PT", "RO", "SE", "SI", "SK"];
19
+ /** The seller: Dehne Robotik GmbH. Fleetless never charges another EU country's VAT. */
20
+ export declare const SELLER_COUNTRY = "DE";
21
+ /** Germany's VAT rate, in whole percent. */
22
+ export declare const DE_VAT_RATE_PERCENT = 19;
23
+ /** Whether `country` is one of the 27 EU member states. */
24
+ export declare function isEuCountry(country: string): boolean;
25
+ /** EUR in the EU, USD elsewhere. */
26
+ export declare function currencyForCountry(country: string): PlanCurrency;
27
+ /** Who is paying: a company (may hold a VAT ID) or a person (a full name, never a VAT ID). */
28
+ export declare const payerKind: z.ZodEnum<{
29
+ company: "company";
30
+ person: "person";
31
+ }>;
32
+ export type PayerKind = z.infer<typeof payerKind>;
33
+ /** The billing cycle: monthly, or yearly at twelve months for 15 % off (#103). */
34
+ export declare const billingCycle: z.ZodEnum<{
35
+ monthly: "monthly";
36
+ yearly: "yearly";
37
+ }>;
38
+ export type BillingCycle = z.infer<typeof billingCycle>;
39
+ /**
40
+ * How a charge is taxed: `de_standard` (German VAT), `reverse_charge` (0 %,
41
+ * an EU company whose VAT ID VIES confirms) or `outside_eu` (0 %, no
42
+ * reverse-charge note).
43
+ */
44
+ export declare const vatTreatment: z.ZodEnum<{
45
+ de_standard: "de_standard";
46
+ reverse_charge: "reverse_charge";
47
+ outside_eu: "outside_eu";
48
+ }>;
49
+ export type VatTreatment = z.infer<typeof vatTreatment>;
50
+ /**
51
+ * Why `vatFor` refused a payer: `eu_person` (a person outside Germany, in
52
+ * another EU country), `vat_id_required` (a company in another EU country
53
+ * gave no VAT ID) or `vat_id_invalid` (VIES said the given VAT ID is
54
+ * invalid).
55
+ */
56
+ export declare const payerRefusalRule: z.ZodEnum<{
57
+ eu_person: "eu_person";
58
+ vat_id_required: "vat_id_required";
59
+ vat_id_invalid: "vat_id_invalid";
60
+ }>;
61
+ export type PayerRefusalRule = z.infer<typeof payerRefusalRule>;
62
+ /** What `vatFor` decides: allowed with a treatment and rate, or refused with a rule. */
63
+ export type VatDecision = {
64
+ allowed: true;
65
+ treatment: VatTreatment;
66
+ rate_percent: number;
67
+ } | {
68
+ allowed: false;
69
+ rule: PayerRefusalRule;
70
+ };
71
+ /**
72
+ * Who may pay, and the VAT they pay. `vatIdValid`: `null` = no VAT ID
73
+ * given; `true` = VIES valid **or unverified** (VIES unreachable is
74
+ * accepted); `false` = VIES said invalid.
75
+ *
76
+ * Germany is unconditional — company or person, VAT ID optional, 19 %
77
+ * regardless of whether a given ID checks out. A German VAT ID's validity
78
+ * never gates checkout, only the renewal sweep later (dunning);
79
+ * `vatFor` only ever prices the charge in hand.
80
+ */
81
+ export declare function vatFor(input: {
82
+ kind: PayerKind;
83
+ country: string;
84
+ vatIdValid: boolean | null;
85
+ }): VatDecision;
86
+ /** VIES's member-state code: `EL` for `GR`, the country otherwise. */
87
+ export declare function viesCountry(country: string): string;
88
+ /**
89
+ * Upper-case, without spaces, dots and dashes, and without a leading
90
+ * country prefix: the VIES code (`EL` for Greece) or, for Greece only, the
91
+ * address code `GR` as well, since a payer is as likely to type that. `null` for an
92
+ * empty string (trimmed).
93
+ */
94
+ export declare function normalizeVatId(country: string, raw: string): string | null;
95
+ /**
96
+ * Net price of one period: the plan plus each add-on × units, for the
97
+ * cycle and currency. Add-ons count only on Pro — `plans.ts`'s own rule for
98
+ * which plans may buy them at all (`planFeature.addons`). Throws for
99
+ * `enterprise`: its price is `null`, sold by contract, and self-service
100
+ * never charges it.
101
+ */
102
+ export declare function periodNetCents(input: {
103
+ plan: PlanId;
104
+ addons: OrgAddons;
105
+ cycle: BillingCycle;
106
+ currency: PlanCurrency;
107
+ }): number;
108
+ /** `Math.round(priceCents * remainingDays / periodDays)` — the one rounding every proration in this module uses. */
109
+ export declare function prorateCents(priceCents: number, remainingDays: number, periodDays: number): number;
110
+ /** `Math.round(netCents * ratePercent / 100)`. */
111
+ export declare function vatCents(netCents: number, ratePercent: number): number;
112
+ /** One charge's amounts, in integer cents, excluding and including VAT. */
113
+ export interface ChargeAmounts {
114
+ net_cents: number;
115
+ vat_cents: number;
116
+ gross_cents: number;
117
+ }
118
+ /** Net, VAT (`vatCents`) and gross for one charge. */
119
+ export declare function chargeAmounts(netCents: number, ratePercent: number): ChargeAmounts;
120
+ /** Milliseconds in a day. */
121
+ export declare const DAY_MS = 86400000;
122
+ /** Whole days between `start` and `end` (`Math.round`). */
123
+ export declare function periodDays(start: Date, end: Date): number;
124
+ /** Days left until `end`, as of `now` (`Math.ceil`), clamped to `[0, days]`. */
125
+ export declare function remainingDays(now: Date, end: Date, days: number): number;
126
+ /** A billing state: plan, add-ons and cycle — enough to price one period, or compare two for `changeNetCents`. */
127
+ export interface BillingState {
128
+ plan: PlanId;
129
+ addons: OrgAddons;
130
+ cycle: BillingCycle;
131
+ }
132
+ /**
133
+ * The net amount charged NOW for moving `from` → `to` within the period
134
+ * — increases are charged at once, decreases wait for the period's end,
135
+ * nothing is credited. Three branches, in this order:
136
+ *
137
+ * 1. **Monthly → yearly**: the full yearly price of `to` (plan plus
138
+ * add-ons, Pro only) minus the unused share of `from`'s monthly price,
139
+ * floored at 0. The period restarts today with a new anchor, so this
140
+ * is the only branch that prices `to` and `from` on different cycles.
141
+ * 2. **Yearly → monthly**: the reverse is a cycle *decrease* — charged 0
142
+ * now, stored as `next_cycle` and applied at the period's end, like
143
+ * every other decrease.
144
+ * 3. **Same cycle**: the increase only — the plan difference when `to` is
145
+ * the higher plan (`PLAN_ORDER`), plus each add-on's added units × its
146
+ * unit price, summed and prorated once over the remaining days. A plan
147
+ * decrease and fewer add-ons contribute 0; add-ons count only when
148
+ * `to.plan` is `pro`, and units held on a plan other than Pro count as
149
+ * none.
150
+ */
151
+ export declare function changeNetCents(input: {
152
+ from: BillingState;
153
+ to: BillingState;
154
+ currency: PlanCurrency;
155
+ periodStart: Date;
156
+ periodEnd: Date;
157
+ now: Date;
158
+ }): number;
159
+ /** One line of a `CheckoutQuote`: the plan, or one add-on, with its quantity and both amounts. */
160
+ export interface QuoteLine {
161
+ item: 'plan' | AddonKey;
162
+ quantity: number;
163
+ net_cents: number;
164
+ gross_cents: number;
165
+ }
166
+ /** The first charge of a checkout, broken into lines, in the cycle and currency it is quoted in. */
167
+ export interface CheckoutQuote extends ChargeAmounts {
168
+ lines: QuoteLine[];
169
+ rate_percent: number;
170
+ currency: PlanCurrency;
171
+ cycle: BillingCycle;
172
+ }
173
+ /**
174
+ * The first charge of a checkout: one full period of `plan` + `addons`.
175
+ * One line for the plan, then one line per add-on actually bought
176
+ * (quantity 0 is omitted, not a zero-amount line).
177
+ */
178
+ export declare function checkoutQuote(input: {
179
+ plan: 'plus' | 'pro';
180
+ addons: OrgAddons;
181
+ cycle: BillingCycle;
182
+ currency: PlanCurrency;
183
+ rate_percent: number;
184
+ }): CheckoutQuote;
185
+ /** Dunning after a failed renewal: retries on these days after the charge's due date. */
186
+ export declare const BILLING_RETRY_DAYS: readonly [3, 7];
187
+ /** The day, after the charge's due date, the org is locked when still unpaid. */
188
+ export declare const BILLING_LOCK_DAY = 14;
189
+ /** A billing address. `country` gates VAT (`vatFor`) and currency (`currencyForCountry`). */
190
+ export declare const billingAddress: z.ZodObject<{
191
+ line1: z.ZodString;
192
+ line2: z.ZodNullable<z.ZodString>;
193
+ postal_code: z.ZodString;
194
+ city: z.ZodString;
195
+ country: z.ZodString;
196
+ }, z.core.$strict>;
197
+ export type BillingAddress = z.infer<typeof billingAddress>;
198
+ /**
199
+ * Who is paying: a `company` (may hold a VAT
200
+ * ID, checked through VIES) or a `person` (full name, never a VAT ID — only
201
+ * a company can be VAT-registered). The discriminant decides which other
202
+ * fields exist at all, so a person cannot even send `vat_id` or
203
+ * `company_name` — there is no field for `.strict()` to refuse, the shape
204
+ * itself has none.
205
+ */
206
+ export declare const billingDetails: z.ZodDiscriminatedUnion<[z.ZodObject<{
207
+ kind: z.ZodLiteral<"company">;
208
+ company_name: z.ZodString;
209
+ vat_id: z.ZodNullable<z.ZodString>;
210
+ address: z.ZodObject<{
211
+ line1: z.ZodString;
212
+ line2: z.ZodNullable<z.ZodString>;
213
+ postal_code: z.ZodString;
214
+ city: z.ZodString;
215
+ country: z.ZodString;
216
+ }, z.core.$strict>;
217
+ invoice_email: z.ZodEmail;
218
+ }, z.core.$strict>, z.ZodObject<{
219
+ kind: z.ZodLiteral<"person">;
220
+ full_name: z.ZodString;
221
+ address: z.ZodObject<{
222
+ line1: z.ZodString;
223
+ line2: z.ZodNullable<z.ZodString>;
224
+ postal_code: z.ZodString;
225
+ city: z.ZodString;
226
+ country: z.ZodString;
227
+ }, z.core.$strict>;
228
+ invoice_email: z.ZodEmail;
229
+ }, z.core.$strict>], "kind">;
230
+ export type BillingDetails = z.infer<typeof billingDetails>;
231
+ /**
232
+ * `POST /api/billing/checkout`'s body: the plan and cycle to buy — Basic is
233
+ * free and never checked out — optional add-ons (Pro only; named on `plus`,
234
+ * or without `planFeature.addons`, is `400 validation_error`), the payer,
235
+ * and the terms and withdrawal confirmations: `accept_terms` is
236
+ * always required; `accept_withdrawal` is required for a person and refused
237
+ * for a company, which has no consumer right of withdrawal to confirm.
238
+ */
239
+ export declare const checkoutRequest: z.ZodObject<{
240
+ plan: z.ZodEnum<{
241
+ plus: "plus";
242
+ pro: "pro";
243
+ }>;
244
+ cycle: z.ZodEnum<{
245
+ monthly: "monthly";
246
+ yearly: "yearly";
247
+ }>;
248
+ addons: z.ZodOptional<z.ZodObject<{
249
+ seats: z.ZodOptional<z.ZodNumber>;
250
+ robots: z.ZodOptional<z.ZodNumber>;
251
+ apps: z.ZodOptional<z.ZodNumber>;
252
+ app_user_packs: z.ZodOptional<z.ZodNumber>;
253
+ live_video_packs: z.ZodOptional<z.ZodNumber>;
254
+ }, z.core.$strict>>;
255
+ billing: z.ZodDiscriminatedUnion<[z.ZodObject<{
256
+ kind: z.ZodLiteral<"company">;
257
+ company_name: z.ZodString;
258
+ vat_id: z.ZodNullable<z.ZodString>;
259
+ address: z.ZodObject<{
260
+ line1: z.ZodString;
261
+ line2: z.ZodNullable<z.ZodString>;
262
+ postal_code: z.ZodString;
263
+ city: z.ZodString;
264
+ country: z.ZodString;
265
+ }, z.core.$strict>;
266
+ invoice_email: z.ZodEmail;
267
+ }, z.core.$strict>, z.ZodObject<{
268
+ kind: z.ZodLiteral<"person">;
269
+ full_name: z.ZodString;
270
+ address: z.ZodObject<{
271
+ line1: z.ZodString;
272
+ line2: z.ZodNullable<z.ZodString>;
273
+ postal_code: z.ZodString;
274
+ city: z.ZodString;
275
+ country: z.ZodString;
276
+ }, z.core.$strict>;
277
+ invoice_email: z.ZodEmail;
278
+ }, z.core.$strict>], "kind">;
279
+ accept_terms: z.ZodLiteral<true>;
280
+ accept_withdrawal: z.ZodOptional<z.ZodLiteral<true>>;
281
+ }, z.core.$strict>;
282
+ export type CheckoutRequest = z.infer<typeof checkoutRequest>;
283
+ /** `POST /api/billing/checkout`'s answer: where to send the caller's browser. */
284
+ export declare const checkoutResponse: z.ZodObject<{
285
+ checkout_id: z.ZodUUID;
286
+ checkout_url: z.ZodURL;
287
+ }, z.core.$strip>;
288
+ export type CheckoutResponse = z.infer<typeof checkoutResponse>;
289
+ /** `GET /api/billing/checkout/:id`'s answer: the return page's poll. */
290
+ export declare const checkoutStatus: z.ZodObject<{
291
+ checkout_id: z.ZodUUID;
292
+ status: z.ZodEnum<{
293
+ failed: "failed";
294
+ pending: "pending";
295
+ paid: "paid";
296
+ canceled: "canceled";
297
+ expired: "expired";
298
+ }>;
299
+ purpose: z.ZodEnum<{
300
+ upgrade: "upgrade";
301
+ payment_method: "payment_method";
302
+ invoice: "invoice";
303
+ }>;
304
+ plan: z.ZodEnum<{
305
+ basic: "basic";
306
+ plus: "plus";
307
+ pro: "pro";
308
+ enterprise: "enterprise";
309
+ }>;
310
+ }, z.core.$strip>;
311
+ export type CheckoutStatus = z.infer<typeof checkoutStatus>;
312
+ /** VIES's answer to a VAT-ID check: `unverified` when VIES could not be reached in time. */
313
+ export declare const vatIdStatus: z.ZodEnum<{
314
+ valid: "valid";
315
+ unverified: "unverified";
316
+ invalid: "invalid";
317
+ }>;
318
+ export type VatIdStatus = z.infer<typeof vatIdStatus>;
319
+ /** `POST /api/billing/vat-id/check`'s body: the VAT-ID-on-blur check the checkout and `PATCH /api/billing/details` both use. */
320
+ export declare const vatIdCheckRequest: z.ZodObject<{
321
+ country: z.ZodString;
322
+ vat_id: z.ZodString;
323
+ }, z.core.$strict>;
324
+ export type VatIdCheckRequest = z.infer<typeof vatIdCheckRequest>;
325
+ /** `POST /api/billing/vat-id/check`'s answer. */
326
+ export declare const vatIdCheckResponse: z.ZodObject<{
327
+ status: z.ZodEnum<{
328
+ valid: "valid";
329
+ unverified: "unverified";
330
+ invalid: "invalid";
331
+ }>;
332
+ vat_id: z.ZodString;
333
+ name: z.ZodNullable<z.ZodString>;
334
+ }, z.core.$strip>;
335
+ export type VatIdCheckResponse = z.infer<typeof vatIdCheckResponse>;
336
+ /**
337
+ * `POST /api/billing/change`'s body: the **absolute** target state, never a
338
+ * delta — the route compares it with the org's current state
339
+ * and splits the difference into what is charged now and what is only
340
+ * scheduled. At least one of `plan`, `cycle` or `addons` must be named; the
341
+ * `.refine()` below says so in prose rather than in the JSON Schema this
342
+ * exports as, the same discipline `auditQuery`'s pair already follows —
343
+ * `.refine()` has no JSON Schema rendering.
344
+ */
345
+ export declare const billingChangeRequest: z.ZodObject<{
346
+ plan: z.ZodOptional<z.ZodEnum<{
347
+ plus: "plus";
348
+ pro: "pro";
349
+ }>>;
350
+ cycle: z.ZodOptional<z.ZodEnum<{
351
+ monthly: "monthly";
352
+ yearly: "yearly";
353
+ }>>;
354
+ addons: z.ZodOptional<z.ZodObject<{
355
+ seats: z.ZodOptional<z.ZodNumber>;
356
+ robots: z.ZodOptional<z.ZodNumber>;
357
+ apps: z.ZodOptional<z.ZodNumber>;
358
+ app_user_packs: z.ZodOptional<z.ZodNumber>;
359
+ live_video_packs: z.ZodOptional<z.ZodNumber>;
360
+ }, z.core.$strict>>;
361
+ }, z.core.$strict>;
362
+ export type BillingChangeRequest = z.infer<typeof billingChangeRequest>;
363
+ /** `POST /api/billing/cancel`'s body — optional, hence `requestOptional` on the route entry. */
364
+ export declare const billingCancelRequest: z.ZodObject<{
365
+ reason: z.ZodOptional<z.ZodString>;
366
+ }, z.core.$strict>;
367
+ export type BillingCancelRequest = z.infer<typeof billingCancelRequest>;
368
+ /** `PATCH /api/billing/details`'s body: the invoice email and the VAT ID, the two fields an owner edits after checkout. */
369
+ export declare const billingDetailsUpdate: z.ZodObject<{
370
+ invoice_email: z.ZodOptional<z.ZodEmail>;
371
+ vat_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
372
+ }, z.core.$strict>;
373
+ export type BillingDetailsUpdate = z.infer<typeof billingDetailsUpdate>;
374
+ /** `POST /api/billing/payment-method`'s body. */
375
+ export declare const paymentMethodChangeRequest: z.ZodObject<{
376
+ method: z.ZodEnum<{
377
+ card: "card";
378
+ paypal: "paypal";
379
+ sepa: "sepa";
380
+ }>;
381
+ }, z.core.$strict>;
382
+ export type PaymentMethodChangeRequest = z.infer<typeof paymentMethodChangeRequest>;
383
+ /** The billing account's own status, distinct from the org's plan: `billing_accounts` holds no plan, currency or period of its own. */
384
+ export declare const billingAccountStatus: z.ZodEnum<{
385
+ active: "active";
386
+ pending: "pending";
387
+ canceled: "canceled";
388
+ past_due: "past_due";
389
+ }>;
390
+ export type BillingAccountStatus = z.infer<typeof billingAccountStatus>;
391
+ /** The payment method on file, read from the active Mollie mandate — never a card or bank number, only its display fields. */
392
+ export declare const paymentMethod: z.ZodDiscriminatedUnion<[z.ZodObject<{
393
+ kind: z.ZodLiteral<"card">;
394
+ brand: z.ZodString;
395
+ last4: z.ZodString;
396
+ expires: z.ZodString;
397
+ }, z.core.$strip>, z.ZodObject<{
398
+ kind: z.ZodLiteral<"sepa">;
399
+ holder: z.ZodString;
400
+ iban_last4: z.ZodString;
401
+ }, z.core.$strip>, z.ZodObject<{
402
+ kind: z.ZodLiteral<"paypal">;
403
+ account: z.ZodString;
404
+ }, z.core.$strip>], "kind">;
405
+ export type PaymentMethod = z.infer<typeof paymentMethod>;
406
+ /** An invoice's status: `open` until paid, or `uncollectible` after a fallback to Basic with an unpaid balance. */
407
+ export declare const invoiceStatus: z.ZodEnum<{
408
+ paid: "paid";
409
+ open: "open";
410
+ uncollectible: "uncollectible";
411
+ }>;
412
+ export type InvoiceStatus = z.infer<typeof invoiceStatus>;
413
+ /** One invoice, rendered by the cloud: the number is gapless, `FL-<year>-<seq>`. */
414
+ export declare const billingInvoice: z.ZodObject<{
415
+ id: z.ZodUUID;
416
+ number: z.ZodString;
417
+ issued_at: z.ZodISODateTime;
418
+ status: z.ZodEnum<{
419
+ paid: "paid";
420
+ open: "open";
421
+ uncollectible: "uncollectible";
422
+ }>;
423
+ currency: z.ZodEnum<{
424
+ eur: "eur";
425
+ usd: "usd";
426
+ }>;
427
+ net_cents: z.ZodNumber;
428
+ vat_rate_percent: z.ZodNumber;
429
+ vat_cents: z.ZodNumber;
430
+ gross_cents: z.ZodNumber;
431
+ }, z.core.$strip>;
432
+ export type BillingInvoice = z.infer<typeof billingInvoice>;
433
+ /**
434
+ * The org's billing account: the payer, the VAT treatment, the cycle and
435
+ * period, what is scheduled for the period's end and dunning
436
+ *, when a charge is overdue. `orgs.plan`, `orgs.currency` and
437
+ * `orgs.period_ends_at` stay the single source of truth for the plan itself
438
+ * (#103) — nothing here duplicates them.
439
+ */
440
+ export declare const billingAccount: z.ZodObject<{
441
+ payer: z.ZodDiscriminatedUnion<[z.ZodObject<{
442
+ kind: z.ZodLiteral<"company">;
443
+ company_name: z.ZodString;
444
+ vat_id: z.ZodNullable<z.ZodString>;
445
+ address: z.ZodObject<{
446
+ line1: z.ZodString;
447
+ line2: z.ZodNullable<z.ZodString>;
448
+ postal_code: z.ZodString;
449
+ city: z.ZodString;
450
+ country: z.ZodString;
451
+ }, z.core.$strict>;
452
+ invoice_email: z.ZodEmail;
453
+ }, z.core.$strict>, z.ZodObject<{
454
+ kind: z.ZodLiteral<"person">;
455
+ full_name: z.ZodString;
456
+ address: z.ZodObject<{
457
+ line1: z.ZodString;
458
+ line2: z.ZodNullable<z.ZodString>;
459
+ postal_code: z.ZodString;
460
+ city: z.ZodString;
461
+ country: z.ZodString;
462
+ }, z.core.$strict>;
463
+ invoice_email: z.ZodEmail;
464
+ }, z.core.$strict>], "kind">;
465
+ vat_id_status: z.ZodNullable<z.ZodEnum<{
466
+ valid: "valid";
467
+ unverified: "unverified";
468
+ invalid: "invalid";
469
+ }>>;
470
+ vat: z.ZodObject<{
471
+ treatment: z.ZodEnum<{
472
+ de_standard: "de_standard";
473
+ reverse_charge: "reverse_charge";
474
+ outside_eu: "outside_eu";
475
+ }>;
476
+ rate_percent: z.ZodNumber;
477
+ }, z.core.$strip>;
478
+ currency: z.ZodEnum<{
479
+ eur: "eur";
480
+ usd: "usd";
481
+ }>;
482
+ cycle: z.ZodEnum<{
483
+ monthly: "monthly";
484
+ yearly: "yearly";
485
+ }>;
486
+ status: z.ZodEnum<{
487
+ active: "active";
488
+ pending: "pending";
489
+ canceled: "canceled";
490
+ past_due: "past_due";
491
+ }>;
492
+ period_starts_at: z.ZodNullable<z.ZodISODateTime>;
493
+ period_ends_at: z.ZodNullable<z.ZodISODateTime>;
494
+ next_charge: z.ZodNullable<z.ZodObject<{
495
+ at: z.ZodISODateTime;
496
+ net_cents: z.ZodNumber;
497
+ vat_cents: z.ZodNumber;
498
+ gross_cents: z.ZodNumber;
499
+ }, z.core.$strip>>;
500
+ scheduled: z.ZodObject<{
501
+ cycle: z.ZodNullable<z.ZodEnum<{
502
+ monthly: "monthly";
503
+ yearly: "yearly";
504
+ }>>;
505
+ addons: z.ZodNullable<z.ZodObject<{
506
+ seats: z.ZodNumber;
507
+ robots: z.ZodNumber;
508
+ apps: z.ZodNumber;
509
+ app_user_packs: z.ZodNumber;
510
+ live_video_packs: z.ZodNumber;
511
+ }, z.core.$strip>>;
512
+ }, z.core.$strip>;
513
+ dunning: z.ZodNullable<z.ZodObject<{
514
+ invoice_id: z.ZodUUID;
515
+ gross_cents: z.ZodNumber;
516
+ due_at: z.ZodISODateTime;
517
+ next_retry_at: z.ZodNullable<z.ZodISODateTime>;
518
+ lock_at: z.ZodISODateTime;
519
+ failure: z.ZodNullable<z.ZodString>;
520
+ }, z.core.$strip>>;
521
+ }, z.core.$strip>;
522
+ export type BillingAccount = z.infer<typeof billingAccount>;
523
+ /** `GET /api/billing`'s answer, and what every other billing route hands back after a change. */
524
+ export declare const billingView: z.ZodObject<{
525
+ available: z.ZodBoolean;
526
+ account: z.ZodNullable<z.ZodObject<{
527
+ payer: z.ZodDiscriminatedUnion<[z.ZodObject<{
528
+ kind: z.ZodLiteral<"company">;
529
+ company_name: z.ZodString;
530
+ vat_id: z.ZodNullable<z.ZodString>;
531
+ address: z.ZodObject<{
532
+ line1: z.ZodString;
533
+ line2: z.ZodNullable<z.ZodString>;
534
+ postal_code: z.ZodString;
535
+ city: z.ZodString;
536
+ country: z.ZodString;
537
+ }, z.core.$strict>;
538
+ invoice_email: z.ZodEmail;
539
+ }, z.core.$strict>, z.ZodObject<{
540
+ kind: z.ZodLiteral<"person">;
541
+ full_name: z.ZodString;
542
+ address: z.ZodObject<{
543
+ line1: z.ZodString;
544
+ line2: z.ZodNullable<z.ZodString>;
545
+ postal_code: z.ZodString;
546
+ city: z.ZodString;
547
+ country: z.ZodString;
548
+ }, z.core.$strict>;
549
+ invoice_email: z.ZodEmail;
550
+ }, z.core.$strict>], "kind">;
551
+ vat_id_status: z.ZodNullable<z.ZodEnum<{
552
+ valid: "valid";
553
+ unverified: "unverified";
554
+ invalid: "invalid";
555
+ }>>;
556
+ vat: z.ZodObject<{
557
+ treatment: z.ZodEnum<{
558
+ de_standard: "de_standard";
559
+ reverse_charge: "reverse_charge";
560
+ outside_eu: "outside_eu";
561
+ }>;
562
+ rate_percent: z.ZodNumber;
563
+ }, z.core.$strip>;
564
+ currency: z.ZodEnum<{
565
+ eur: "eur";
566
+ usd: "usd";
567
+ }>;
568
+ cycle: z.ZodEnum<{
569
+ monthly: "monthly";
570
+ yearly: "yearly";
571
+ }>;
572
+ status: z.ZodEnum<{
573
+ active: "active";
574
+ pending: "pending";
575
+ canceled: "canceled";
576
+ past_due: "past_due";
577
+ }>;
578
+ period_starts_at: z.ZodNullable<z.ZodISODateTime>;
579
+ period_ends_at: z.ZodNullable<z.ZodISODateTime>;
580
+ next_charge: z.ZodNullable<z.ZodObject<{
581
+ at: z.ZodISODateTime;
582
+ net_cents: z.ZodNumber;
583
+ vat_cents: z.ZodNumber;
584
+ gross_cents: z.ZodNumber;
585
+ }, z.core.$strip>>;
586
+ scheduled: z.ZodObject<{
587
+ cycle: z.ZodNullable<z.ZodEnum<{
588
+ monthly: "monthly";
589
+ yearly: "yearly";
590
+ }>>;
591
+ addons: z.ZodNullable<z.ZodObject<{
592
+ seats: z.ZodNumber;
593
+ robots: z.ZodNumber;
594
+ apps: z.ZodNumber;
595
+ app_user_packs: z.ZodNumber;
596
+ live_video_packs: z.ZodNumber;
597
+ }, z.core.$strip>>;
598
+ }, z.core.$strip>;
599
+ dunning: z.ZodNullable<z.ZodObject<{
600
+ invoice_id: z.ZodUUID;
601
+ gross_cents: z.ZodNumber;
602
+ due_at: z.ZodISODateTime;
603
+ next_retry_at: z.ZodNullable<z.ZodISODateTime>;
604
+ lock_at: z.ZodISODateTime;
605
+ failure: z.ZodNullable<z.ZodString>;
606
+ }, z.core.$strip>>;
607
+ }, z.core.$strip>>;
608
+ payment_method: z.ZodNullable<z.ZodDiscriminatedUnion<[z.ZodObject<{
609
+ kind: z.ZodLiteral<"card">;
610
+ brand: z.ZodString;
611
+ last4: z.ZodString;
612
+ expires: z.ZodString;
613
+ }, z.core.$strip>, z.ZodObject<{
614
+ kind: z.ZodLiteral<"sepa">;
615
+ holder: z.ZodString;
616
+ iban_last4: z.ZodString;
617
+ }, z.core.$strip>, z.ZodObject<{
618
+ kind: z.ZodLiteral<"paypal">;
619
+ account: z.ZodString;
620
+ }, z.core.$strip>], "kind">>;
621
+ invoices: z.ZodArray<z.ZodObject<{
622
+ id: z.ZodUUID;
623
+ number: z.ZodString;
624
+ issued_at: z.ZodISODateTime;
625
+ status: z.ZodEnum<{
626
+ paid: "paid";
627
+ open: "open";
628
+ uncollectible: "uncollectible";
629
+ }>;
630
+ currency: z.ZodEnum<{
631
+ eur: "eur";
632
+ usd: "usd";
633
+ }>;
634
+ net_cents: z.ZodNumber;
635
+ vat_rate_percent: z.ZodNumber;
636
+ vat_cents: z.ZodNumber;
637
+ gross_cents: z.ZodNumber;
638
+ }, z.core.$strip>>;
639
+ }, z.core.$strip>;
640
+ export type BillingView = z.infer<typeof billingView>;
641
+ /** `POST /api/billing/change`'s answer: the billing view afterwards, and what was charged right now, if anything. */
642
+ export declare const billingChangeResponse: z.ZodObject<{
643
+ billing: z.ZodObject<{
644
+ available: z.ZodBoolean;
645
+ account: z.ZodNullable<z.ZodObject<{
646
+ payer: z.ZodDiscriminatedUnion<[z.ZodObject<{
647
+ kind: z.ZodLiteral<"company">;
648
+ company_name: z.ZodString;
649
+ vat_id: z.ZodNullable<z.ZodString>;
650
+ address: z.ZodObject<{
651
+ line1: z.ZodString;
652
+ line2: z.ZodNullable<z.ZodString>;
653
+ postal_code: z.ZodString;
654
+ city: z.ZodString;
655
+ country: z.ZodString;
656
+ }, z.core.$strict>;
657
+ invoice_email: z.ZodEmail;
658
+ }, z.core.$strict>, z.ZodObject<{
659
+ kind: z.ZodLiteral<"person">;
660
+ full_name: z.ZodString;
661
+ address: z.ZodObject<{
662
+ line1: z.ZodString;
663
+ line2: z.ZodNullable<z.ZodString>;
664
+ postal_code: z.ZodString;
665
+ city: z.ZodString;
666
+ country: z.ZodString;
667
+ }, z.core.$strict>;
668
+ invoice_email: z.ZodEmail;
669
+ }, z.core.$strict>], "kind">;
670
+ vat_id_status: z.ZodNullable<z.ZodEnum<{
671
+ valid: "valid";
672
+ unverified: "unverified";
673
+ invalid: "invalid";
674
+ }>>;
675
+ vat: z.ZodObject<{
676
+ treatment: z.ZodEnum<{
677
+ de_standard: "de_standard";
678
+ reverse_charge: "reverse_charge";
679
+ outside_eu: "outside_eu";
680
+ }>;
681
+ rate_percent: z.ZodNumber;
682
+ }, z.core.$strip>;
683
+ currency: z.ZodEnum<{
684
+ eur: "eur";
685
+ usd: "usd";
686
+ }>;
687
+ cycle: z.ZodEnum<{
688
+ monthly: "monthly";
689
+ yearly: "yearly";
690
+ }>;
691
+ status: z.ZodEnum<{
692
+ active: "active";
693
+ pending: "pending";
694
+ canceled: "canceled";
695
+ past_due: "past_due";
696
+ }>;
697
+ period_starts_at: z.ZodNullable<z.ZodISODateTime>;
698
+ period_ends_at: z.ZodNullable<z.ZodISODateTime>;
699
+ next_charge: z.ZodNullable<z.ZodObject<{
700
+ at: z.ZodISODateTime;
701
+ net_cents: z.ZodNumber;
702
+ vat_cents: z.ZodNumber;
703
+ gross_cents: z.ZodNumber;
704
+ }, z.core.$strip>>;
705
+ scheduled: z.ZodObject<{
706
+ cycle: z.ZodNullable<z.ZodEnum<{
707
+ monthly: "monthly";
708
+ yearly: "yearly";
709
+ }>>;
710
+ addons: z.ZodNullable<z.ZodObject<{
711
+ seats: z.ZodNumber;
712
+ robots: z.ZodNumber;
713
+ apps: z.ZodNumber;
714
+ app_user_packs: z.ZodNumber;
715
+ live_video_packs: z.ZodNumber;
716
+ }, z.core.$strip>>;
717
+ }, z.core.$strip>;
718
+ dunning: z.ZodNullable<z.ZodObject<{
719
+ invoice_id: z.ZodUUID;
720
+ gross_cents: z.ZodNumber;
721
+ due_at: z.ZodISODateTime;
722
+ next_retry_at: z.ZodNullable<z.ZodISODateTime>;
723
+ lock_at: z.ZodISODateTime;
724
+ failure: z.ZodNullable<z.ZodString>;
725
+ }, z.core.$strip>>;
726
+ }, z.core.$strip>>;
727
+ payment_method: z.ZodNullable<z.ZodDiscriminatedUnion<[z.ZodObject<{
728
+ kind: z.ZodLiteral<"card">;
729
+ brand: z.ZodString;
730
+ last4: z.ZodString;
731
+ expires: z.ZodString;
732
+ }, z.core.$strip>, z.ZodObject<{
733
+ kind: z.ZodLiteral<"sepa">;
734
+ holder: z.ZodString;
735
+ iban_last4: z.ZodString;
736
+ }, z.core.$strip>, z.ZodObject<{
737
+ kind: z.ZodLiteral<"paypal">;
738
+ account: z.ZodString;
739
+ }, z.core.$strip>], "kind">>;
740
+ invoices: z.ZodArray<z.ZodObject<{
741
+ id: z.ZodUUID;
742
+ number: z.ZodString;
743
+ issued_at: z.ZodISODateTime;
744
+ status: z.ZodEnum<{
745
+ paid: "paid";
746
+ open: "open";
747
+ uncollectible: "uncollectible";
748
+ }>;
749
+ currency: z.ZodEnum<{
750
+ eur: "eur";
751
+ usd: "usd";
752
+ }>;
753
+ net_cents: z.ZodNumber;
754
+ vat_rate_percent: z.ZodNumber;
755
+ vat_cents: z.ZodNumber;
756
+ gross_cents: z.ZodNumber;
757
+ }, z.core.$strip>>;
758
+ }, z.core.$strip>;
759
+ charged: z.ZodNullable<z.ZodObject<{
760
+ id: z.ZodUUID;
761
+ number: z.ZodString;
762
+ issued_at: z.ZodISODateTime;
763
+ status: z.ZodEnum<{
764
+ paid: "paid";
765
+ open: "open";
766
+ uncollectible: "uncollectible";
767
+ }>;
768
+ currency: z.ZodEnum<{
769
+ eur: "eur";
770
+ usd: "usd";
771
+ }>;
772
+ net_cents: z.ZodNumber;
773
+ vat_rate_percent: z.ZodNumber;
774
+ vat_cents: z.ZodNumber;
775
+ gross_cents: z.ZodNumber;
776
+ }, z.core.$strip>>;
777
+ }, z.core.$strip>;
778
+ export type BillingChangeResponse = z.infer<typeof billingChangeResponse>;