@taxora/sdk 1.7.1 → 1.9.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.cjs CHANGED
@@ -24,12 +24,14 @@ __export(index_exports, {
24
24
  AuthEndpoint: () => AuthEndpoint,
25
25
  AuthRetryHttpClient: () => AuthRetryHttpClient,
26
26
  AuthenticationException: () => AuthenticationException,
27
+ BillingEndpoint: () => BillingEndpoint,
27
28
  CompanyAddress: () => CompanyAddress,
28
29
  CompanyEndpoint: () => CompanyEndpoint,
29
30
  ComplianceDocumentType: () => ComplianceDocumentType,
30
31
  ComplianceEnrollment: () => ComplianceEnrollment,
31
32
  ComplianceEnrollmentPage: () => ComplianceEnrollmentPage,
32
33
  ComplianceEnrollmentStatus: () => ComplianceEnrollmentStatus,
34
+ ComplianceOfferings: () => ComplianceOfferings,
33
35
  ComplianceService: () => ComplianceService,
34
36
  ComplianceTaxReport: () => ComplianceTaxReport,
35
37
  ComplianceTaxReportPage: () => ComplianceTaxReportPage,
@@ -63,6 +65,8 @@ __export(index_exports, {
63
65
  SmartEnrichmentHistoryRow: () => SmartEnrichmentHistoryRow,
64
66
  SmartEnrichmentJob: () => SmartEnrichmentJob,
65
67
  SmartEnrichmentMode: () => SmartEnrichmentMode,
68
+ SmartEnrichmentRecheck: () => SmartEnrichmentRecheck,
69
+ SmartEnrichmentRecheckState: () => SmartEnrichmentRecheckState,
66
70
  SmartEnrichmentRejectionReason: () => SmartEnrichmentRejectionReason,
67
71
  SmartEnrichmentResource: () => SmartEnrichmentResource,
68
72
  SmartEnrichmentStatistics: () => SmartEnrichmentStatistics,
@@ -71,6 +75,8 @@ __export(index_exports, {
71
75
  TaxoraClientFactory: () => TaxoraClientFactory,
72
76
  TaxoraException: () => TaxoraException,
73
77
  Token: () => Token,
78
+ UsageSummary: () => UsageSummary,
79
+ UsageSummaryPage: () => UsageSummaryPage,
74
80
  ValidationException: () => ValidationException,
75
81
  VatCertificateExport: () => VatCertificateExport,
76
82
  VatCollection: () => VatCollection,
@@ -99,6 +105,7 @@ __export(index_exports, {
99
105
  generateWebhookSignatureHeader: () => generateWebhookSignatureHeader,
100
106
  getBaseUrl: () => getBaseUrl,
101
107
  getFailedVatStates: () => getFailedVatStates,
108
+ isTransactionBuyerRejected: () => isTransactionBuyerRejected,
102
109
  parseLocalTaxNumbersCsv: () => parseLocalTaxNumbersCsv,
103
110
  parseWebhookSignatureHeader: () => parseWebhookSignatureHeader,
104
111
  toComplianceDocumentType: () => toComplianceDocumentType,
@@ -557,6 +564,213 @@ var AuthEndpoint = class {
557
564
  }
558
565
  };
559
566
 
567
+ // src/dto/UsageSummary.ts
568
+ function asRecord(value) {
569
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
570
+ }
571
+ function asRecordList(value) {
572
+ return Array.isArray(value) ? value.filter((row) => asRecord(row) !== null) : [];
573
+ }
574
+ function asString(value, fallback = "") {
575
+ return typeof value === "string" ? value : fallback;
576
+ }
577
+ function asNullableString(value) {
578
+ return typeof value === "string" ? value : null;
579
+ }
580
+ function asNumber(value) {
581
+ return typeof value === "number" ? value : Number(value ?? 0) || 0;
582
+ }
583
+ function asNullableNumber(value) {
584
+ if (value === null || value === void 0 || value === "") return null;
585
+ const num = Number(value);
586
+ return Number.isFinite(num) ? num : null;
587
+ }
588
+ var UsageSummary = class _UsageSummary {
589
+ constructor(id, companyId, feature, country, regime, billingPeriod, eventCount, billableAmount, state, stateLabel, periodClosedAt, billingTriggeredAt, billedAt, stripeInvoiceId, stripeSubscriptionItemId, billingNotes, events, createdAt, updatedAt) {
590
+ this.id = id;
591
+ this.companyId = companyId;
592
+ this.feature = feature;
593
+ this.country = country;
594
+ this.regime = regime;
595
+ this.billingPeriod = billingPeriod;
596
+ this.eventCount = eventCount;
597
+ this.billableAmount = billableAmount;
598
+ this.state = state;
599
+ this.stateLabel = stateLabel;
600
+ this.periodClosedAt = periodClosedAt;
601
+ this.billingTriggeredAt = billingTriggeredAt;
602
+ this.billedAt = billedAt;
603
+ this.stripeInvoiceId = stripeInvoiceId;
604
+ this.stripeSubscriptionItemId = stripeSubscriptionItemId;
605
+ this.billingNotes = billingNotes;
606
+ this.events = events;
607
+ this.createdAt = createdAt;
608
+ this.updatedAt = updatedAt;
609
+ }
610
+ id;
611
+ companyId;
612
+ feature;
613
+ country;
614
+ regime;
615
+ billingPeriod;
616
+ eventCount;
617
+ billableAmount;
618
+ state;
619
+ stateLabel;
620
+ periodClosedAt;
621
+ billingTriggeredAt;
622
+ billedAt;
623
+ stripeInvoiceId;
624
+ stripeSubscriptionItemId;
625
+ billingNotes;
626
+ events;
627
+ createdAt;
628
+ updatedAt;
629
+ static fromArray(data) {
630
+ const amount = data["billable_amount"];
631
+ return new _UsageSummary(
632
+ asNumber(data["id"]),
633
+ asNumber(data["company_id"]),
634
+ asString(data["feature"]),
635
+ asNullableString(data["country"]),
636
+ asNullableString(data["regime"]),
637
+ asString(data["billing_period"]),
638
+ asNumber(data["event_count"]),
639
+ typeof amount === "string" ? amount : typeof amount === "number" ? String(amount) : null,
640
+ asNullableString(data["state"]),
641
+ asNullableString(data["state_label"]),
642
+ asNullableString(data["period_closed_at"]),
643
+ asNullableString(data["billing_triggered_at"]),
644
+ asNullableString(data["billed_at"]),
645
+ asNullableString(data["stripe_invoice_id"]),
646
+ asNullableString(data["stripe_subscription_item_id"]),
647
+ asNullableString(data["billing_notes"]),
648
+ asRecordList(data["events"]).map((event) => ({
649
+ id: asNumber(event["id"]),
650
+ usageSummaryId: asNullableNumber(event["usage_summary_id"]),
651
+ feature: asString(event["feature"]),
652
+ country: asNullableString(event["country"]),
653
+ regime: asNullableString(event["regime"]),
654
+ billingPeriod: asString(event["billing_period"]),
655
+ resourceType: asNullableString(event["resource_type"]),
656
+ resourceId: asNullableNumber(event["resource_id"]),
657
+ stripeUsageRecordId: asNullableString(event["stripe_usage_record_id"]),
658
+ stripeReportedAt: asNullableString(event["stripe_reported_at"]),
659
+ createdAt: asNullableString(event["created_at"])
660
+ })),
661
+ asNullableString(data["created_at"]),
662
+ asNullableString(data["updated_at"])
663
+ );
664
+ }
665
+ };
666
+ var UsageSummaryPage = class _UsageSummaryPage {
667
+ constructor(rows, currentPage, perPage, total, lastPage) {
668
+ this.rows = rows;
669
+ this.currentPage = currentPage;
670
+ this.perPage = perPage;
671
+ this.total = total;
672
+ this.lastPage = lastPage;
673
+ }
674
+ rows;
675
+ currentPage;
676
+ perPage;
677
+ total;
678
+ lastPage;
679
+ static fromResponse(payload) {
680
+ const obj = asRecord(payload) ?? {};
681
+ const rows = asRecordList(obj["data"]).map(UsageSummary.fromArray);
682
+ const meta = asRecord(obj["meta"]) ?? {};
683
+ const num = (value, fallback) => typeof value === "number" ? value : fallback;
684
+ return new _UsageSummaryPage(
685
+ rows,
686
+ num(meta["current_page"], 1),
687
+ num(meta["per_page"], rows.length),
688
+ num(meta["total"], rows.length),
689
+ num(meta["last_page"], 1)
690
+ );
691
+ }
692
+ [Symbol.iterator]() {
693
+ return this.rows[Symbol.iterator]();
694
+ }
695
+ get length() {
696
+ return this.rows.length;
697
+ }
698
+ };
699
+
700
+ // src/endpoints/BillingEndpoint.ts
701
+ var PERIOD_REGEX = /^\d{4}-(0[1-9]|1[0-2])$/;
702
+ var BillingEndpoint = class {
703
+ constructor(baseUrl, apiKey, tokenStorage, httpClient, retryPolicy = new RetryPolicy()) {
704
+ this.baseUrl = baseUrl;
705
+ this.apiKey = apiKey;
706
+ this.tokenStorage = tokenStorage;
707
+ this.httpClient = httpClient;
708
+ this.retryPolicy = retryPolicy;
709
+ }
710
+ baseUrl;
711
+ apiKey;
712
+ tokenStorage;
713
+ httpClient;
714
+ retryPolicy;
715
+ /** Paginated usage summaries, newest billing period first. `perPage` is clamped to 1-100 server-side. */
716
+ async listUsageSummaries(page = 1, perPage = 25) {
717
+ const params = new URLSearchParams();
718
+ params.set("page", String(page));
719
+ params.set("per_page", String(perPage));
720
+ const data = await this.getJson(`${this.baseUrl}/billing/usage-summaries?${params.toString()}`);
721
+ return UsageSummaryPage.fromResponse(data);
722
+ }
723
+ /**
724
+ * The usage summaries of one billing period (YYYY-MM), one per feature,
725
+ * each with its usage events. A period without usage yields a 404 (HttpException).
726
+ */
727
+ async getUsageSummaries(period) {
728
+ if (!PERIOD_REGEX.test(period)) {
729
+ throw new TaxoraException(`Invalid billing period "${period}". Expected YYYY-MM, e.g. "2026-09".`);
730
+ }
731
+ const data = await this.getJson(`${this.baseUrl}/billing/usage-summaries/${period}`);
732
+ return Array.isArray(data) ? data.filter((row) => typeof row === "object" && row !== null).map(UsageSummary.fromArray) : [];
733
+ }
734
+ buildHeaders() {
735
+ const headers = {
736
+ "Content-Type": "application/json",
737
+ "x-api-key": this.apiKey
738
+ };
739
+ const token = this.tokenStorage.get();
740
+ if (token) {
741
+ headers["Authorization"] = `Bearer ${token.accessToken}`;
742
+ }
743
+ return headers;
744
+ }
745
+ /** GET + envelope unwrap (`{success, data}` → data, which may be an object or an array). */
746
+ async getJson(url) {
747
+ return withRetries(this.retryPolicy, "billing request", async () => {
748
+ const response = await this.httpClient.request("GET", url, { headers: this.buildHeaders() });
749
+ const responseText = await response.text();
750
+ if (!response.ok) {
751
+ throw new HttpException(
752
+ describeApiError(responseText, response.status),
753
+ response.status,
754
+ responseText,
755
+ {},
756
+ response.headers.get("retry-after")
757
+ );
758
+ }
759
+ let parsed;
760
+ try {
761
+ parsed = JSON.parse(responseText);
762
+ } catch {
763
+ throw new HttpException("Invalid JSON response", response.status, responseText);
764
+ }
765
+ if (typeof parsed !== "object" || parsed === null) {
766
+ throw new HttpException("Unexpected response format", response.status, responseText);
767
+ }
768
+ const obj = parsed;
769
+ return obj["data"] !== void 0 && obj["data"] !== null ? obj["data"] : obj;
770
+ });
771
+ }
772
+ };
773
+
560
774
  // src/dto/CompanyResource.ts
561
775
  function normalizeCompanyResource(data) {
562
776
  const apiRateLimit = typeof data["api_rate_limit"] === "number" ? data["api_rate_limit"] : void 0;
@@ -683,13 +897,13 @@ function describeComplianceService(service) {
683
897
  }
684
898
 
685
899
  // src/dto/ComplianceEnrollment.ts
686
- function asString(value, fallback = "") {
900
+ function asString2(value, fallback = "") {
687
901
  return typeof value === "string" ? value : fallback;
688
902
  }
689
- function asNullableString(value) {
903
+ function asNullableString2(value) {
690
904
  return typeof value === "string" ? value : null;
691
905
  }
692
- function asNumber(value) {
906
+ function asNumber2(value) {
693
907
  return typeof value === "number" ? value : Number(value ?? 0) || 0;
694
908
  }
695
909
  var ComplianceEnrollment = class _ComplianceEnrollment {
@@ -736,29 +950,114 @@ var ComplianceEnrollment = class _ComplianceEnrollment {
736
950
  static fromArray(data) {
737
951
  const regimeConfig = typeof data["regime_config"] === "object" && data["regime_config"] !== null && !Array.isArray(data["regime_config"]) ? data["regime_config"] : null;
738
952
  return new _ComplianceEnrollment(
739
- asNumber(data["id"]),
740
- asNumber(data["company_id"]),
741
- asString(data["country"]),
742
- asString(data["regime"]),
743
- asString(data["provider"]),
953
+ asNumber2(data["id"]),
954
+ asNumber2(data["company_id"]),
955
+ asString2(data["country"]),
956
+ asString2(data["regime"]),
957
+ asString2(data["provider"]),
744
958
  toComplianceEnrollmentStatus(data["status"]),
745
- asString(data["status_label"]),
746
- asNullableString(data["status_error"]),
747
- asNullableString(data["provider_account_id"]),
748
- asNullableString(data["tax_id"]),
749
- asNullableString(data["company_register_id"]),
750
- asNullableString(data["company_register_scheme"]),
959
+ asString2(data["status_label"]),
960
+ asNullableString2(data["status_error"]),
961
+ asNullableString2(data["provider_account_id"]),
962
+ asNullableString2(data["tax_id"]),
963
+ asNullableString2(data["company_register_id"]),
964
+ asNullableString2(data["company_register_scheme"]),
751
965
  regimeConfig,
752
- asNullableString(data["reporting_start_date"]),
753
- asNullableString(data["notification_email"]),
966
+ asNullableString2(data["reporting_start_date"]),
967
+ asNullableString2(data["notification_email"]),
754
968
  data["auto_send"] === true,
755
- asNullableString(data["created_at"]),
756
- asNullableString(data["updated_at"]),
969
+ asNullableString2(data["created_at"]),
970
+ asNullableString2(data["updated_at"]),
757
971
  toComplianceService(data["service"])
758
972
  );
759
973
  }
760
974
  };
761
975
 
976
+ // src/dto/ComplianceOfferings.ts
977
+ function asRecord2(value) {
978
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
979
+ }
980
+ function asRecordList2(value) {
981
+ return Array.isArray(value) ? value.filter((row) => asRecord2(row) !== null) : [];
982
+ }
983
+ function asString3(value, fallback = "") {
984
+ return typeof value === "string" ? value : fallback;
985
+ }
986
+ function asNullableString3(value) {
987
+ return typeof value === "string" ? value : null;
988
+ }
989
+ function asNullableNumber2(value) {
990
+ if (typeof value === "number" && Number.isFinite(value)) return value;
991
+ if (typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value))) return Number(value);
992
+ return null;
993
+ }
994
+ function asStringList(value) {
995
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
996
+ }
997
+ function toRequires(value) {
998
+ const record = asRecord2(value);
999
+ return record === null ? null : { country: asString3(record["country"]), service: asString3(record["service"]) };
1000
+ }
1001
+ var ComplianceOfferings = class _ComplianceOfferings {
1002
+ constructor(offerings, coverage, access, accessByCountry) {
1003
+ this.offerings = offerings;
1004
+ this.coverage = coverage;
1005
+ this.access = access;
1006
+ this.accessByCountry = accessByCountry;
1007
+ }
1008
+ offerings;
1009
+ coverage;
1010
+ access;
1011
+ accessByCountry;
1012
+ static fromArray(data) {
1013
+ const offerings = asRecordList2(data["data"]).map((row) => ({
1014
+ country: asString3(row["country"]),
1015
+ service: asString3(row["service"]),
1016
+ currency: asString3(row["currency"], "EUR"),
1017
+ active: row["active"] === true,
1018
+ viaStripe: row["via_stripe"] === true,
1019
+ plan: asNullableString3(row["plan"]),
1020
+ status: asNullableString3(row["status"]),
1021
+ enrolled: row["enrolled"] === true,
1022
+ plans: asRecordList2(row["plans"]).map((plan) => ({
1023
+ key: asString3(plan["key"]),
1024
+ monthlyFee: asNullableNumber2(plan["monthly_fee"]),
1025
+ setupFee: asNullableNumber2(plan["setup_fee"]),
1026
+ usageTiers: Array.isArray(plan["usage_tiers"]) ? plan["usage_tiers"] : [],
1027
+ volumeLimit: plan["volume_limit"] ?? null,
1028
+ contactOnly: plan["contact_only"] === true,
1029
+ checkoutAvailable: plan["checkout_available"] === true,
1030
+ requires: toRequires(plan["requires"]),
1031
+ eligible: plan["eligible"] === true
1032
+ }))
1033
+ }));
1034
+ const coverage = asRecordList2(data["coverage"]).map((row) => ({
1035
+ country: asString3(row["country"]),
1036
+ availability: asString3(row["availability"]),
1037
+ services: asStringList(row["services"]),
1038
+ network: asNullableString3(row["network"]),
1039
+ format: asNullableString3(row["format"]),
1040
+ mandate: asNullableString3(row["mandate"]),
1041
+ support: asString3(row["support"], "yes")
1042
+ }));
1043
+ const access = asRecord2(data["access"]) ?? {};
1044
+ const accessByCountry = {};
1045
+ for (const [country, services] of Object.entries(asRecord2(data["access_by_country"]) ?? {})) {
1046
+ const flags = {};
1047
+ for (const [service, value] of Object.entries(asRecord2(services) ?? {})) {
1048
+ flags[service] = value === true;
1049
+ }
1050
+ accessByCountry[country] = flags;
1051
+ }
1052
+ return new _ComplianceOfferings(
1053
+ offerings,
1054
+ coverage,
1055
+ { eReporting: access["e_reporting"] === true, eInvoicing: access["e_invoicing"] === true },
1056
+ accessByCountry
1057
+ );
1058
+ }
1059
+ };
1060
+
762
1061
  // src/dto/ComplianceEnrollmentPage.ts
763
1062
  var ComplianceEnrollmentPage = class _ComplianceEnrollmentPage {
764
1063
  constructor(rows, currentPage, perPage, total, lastPage) {
@@ -828,16 +1127,16 @@ function describeComplianceTaxReportState(state) {
828
1127
  }
829
1128
 
830
1129
  // src/dto/ComplianceTaxReport.ts
831
- function asString2(value, fallback = "") {
1130
+ function asString4(value, fallback = "") {
832
1131
  return typeof value === "string" ? value : fallback;
833
1132
  }
834
- function asNullableString2(value) {
1133
+ function asNullableString4(value) {
835
1134
  return typeof value === "string" ? value : null;
836
1135
  }
837
- function asNumber2(value) {
1136
+ function asNumber3(value) {
838
1137
  return typeof value === "number" ? value : Number(value ?? 0) || 0;
839
1138
  }
840
- function asNullableNumber(value) {
1139
+ function asNullableNumber3(value) {
841
1140
  return typeof value === "number" ? value : null;
842
1141
  }
843
1142
  function asMoney(value) {
@@ -888,25 +1187,25 @@ var ComplianceTaxReport = class _ComplianceTaxReport {
888
1187
  updatedAt;
889
1188
  static fromArray(data) {
890
1189
  return new _ComplianceTaxReport(
891
- asNumber2(data["id"]),
892
- asNumber2(data["company_id"]),
893
- asNullableNumber(data["compliance_transaction_id"]),
894
- asNullableNumber(data["ledger_id"]),
895
- asString2(data["country"]),
896
- asString2(data["regime"]),
1190
+ asNumber3(data["id"]),
1191
+ asNumber3(data["company_id"]),
1192
+ asNullableNumber3(data["compliance_transaction_id"]),
1193
+ asNullableNumber3(data["ledger_id"]),
1194
+ asString4(data["country"]),
1195
+ asString4(data["regime"]),
897
1196
  toComplianceTaxReportState(data["state"]),
898
- asString2(data["state_label"]),
1197
+ asString4(data["state_label"]),
899
1198
  data["is_terminal"] === true,
900
- asNullableString2(data["provider_tax_report_id"]),
901
- asNullableString2(data["provider_ledger_id"]),
1199
+ asNullableString4(data["provider_tax_report_id"]),
1200
+ asNullableString4(data["provider_ledger_id"]),
902
1201
  asMoney(data["base_amount"]),
903
1202
  asMoney(data["tax_amount"]),
904
1203
  asMoney(data["total_amount"]),
905
- asNullableString2(data["refusal_reason"]),
906
- asNullableString2(data["registered_at"]),
907
- asNullableString2(data["refused_at"]),
908
- asNullableString2(data["created_at"]),
909
- asNullableString2(data["updated_at"])
1204
+ asNullableString4(data["refusal_reason"]),
1205
+ asNullableString4(data["registered_at"]),
1206
+ asNullableString4(data["refused_at"]),
1207
+ asNullableString4(data["created_at"]),
1208
+ asNullableString4(data["updated_at"])
910
1209
  );
911
1210
  }
912
1211
  };
@@ -977,6 +1276,8 @@ var ComplianceTransactionState = {
977
1276
  SENDING: "sending",
978
1277
  SUBMITTED: "submitted",
979
1278
  ERROR: "error",
1279
+ /** E-invoicing only: the buyer cannot receive e-invoices — nothing was sent or billed; send your regular invoice. */
1280
+ NOT_REQUIRED: "not_required",
980
1281
  UNKNOWN: "unknown"
981
1282
  };
982
1283
  var VALUES5 = Object.values(ComplianceTransactionState);
@@ -994,6 +1295,7 @@ var DESCRIPTIONS5 = {
994
1295
  [ComplianceTransactionState.SENDING]: "Submission to the provider in progress.",
995
1296
  [ComplianceTransactionState.SUBMITTED]: "Successfully submitted to the provider.",
996
1297
  [ComplianceTransactionState.ERROR]: "Submission failed. See submissionError.",
1298
+ [ComplianceTransactionState.NOT_REQUIRED]: "The buyer cannot receive e-invoices, so none was sent or billed. Send your regular invoice instead.",
997
1299
  [ComplianceTransactionState.UNKNOWN]: "Unknown state."
998
1300
  };
999
1301
  function describeComplianceTransactionState(state) {
@@ -1032,13 +1334,13 @@ function describeComplianceTransactionType(type) {
1032
1334
  }
1033
1335
 
1034
1336
  // src/dto/ComplianceTransaction.ts
1035
- function asString3(value, fallback = "") {
1337
+ function asString5(value, fallback = "") {
1036
1338
  return typeof value === "string" ? value : fallback;
1037
1339
  }
1038
- function asNullableString3(value) {
1340
+ function asNullableString5(value) {
1039
1341
  return typeof value === "string" ? value : null;
1040
1342
  }
1041
- function asNumber3(value) {
1343
+ function asNumber4(value) {
1042
1344
  return typeof value === "number" ? value : Number(value ?? 0) || 0;
1043
1345
  }
1044
1346
  function asMoney2(value) {
@@ -1046,34 +1348,55 @@ function asMoney2(value) {
1046
1348
  if (typeof value === "number" && Number.isFinite(value)) return String(value);
1047
1349
  return "0.00";
1048
1350
  }
1049
- function asNullableNumber2(value) {
1351
+ function asNullableNumber4(value) {
1050
1352
  if (typeof value === "number" && Number.isFinite(value)) return value;
1051
1353
  if (typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value))) return Number(value);
1052
1354
  return null;
1053
1355
  }
1054
- function asRecord(value) {
1356
+ function asRecord3(value) {
1055
1357
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
1056
1358
  }
1057
- function asRecordList(value) {
1058
- return Array.isArray(value) ? value.filter((row) => asRecord(row) !== null) : [];
1359
+ function asRecordList3(value) {
1360
+ return Array.isArray(value) ? value.filter((row) => asRecord3(row) !== null) : [];
1361
+ }
1362
+ function toInvoicePdf(value) {
1363
+ const pdf = asRecord3(value);
1364
+ if (pdf === null) return null;
1365
+ return {
1366
+ filename: asNullableString5(pdf["filename"]),
1367
+ size: asNullableNumber4(pdf["size"]),
1368
+ attached: pdf["attached"] === true
1369
+ };
1370
+ }
1371
+ function toEurEquivalent(value) {
1372
+ const eur = asRecord3(value);
1373
+ if (eur === null) return null;
1374
+ return {
1375
+ subtotal: asMoney2(eur["subtotal"]),
1376
+ taxAmount: asMoney2(eur["tax_amount"]),
1377
+ total: asMoney2(eur["total"]),
1378
+ rate: asString5(eur["rate"]),
1379
+ rateDate: asNullableString5(eur["rate_date"]),
1380
+ source: asString5(eur["source"], "ECB")
1381
+ };
1059
1382
  }
1060
1383
  function toInvoiceLines(providerPayload) {
1061
- const invoice = asRecord(asRecord(providerPayload)?.["invoice"]);
1062
- return asRecordList(invoice?.["invoice_lines_attributes"]).map((line) => ({
1063
- description: asString3(line["description"]),
1064
- quantity: asNullableNumber2(line["quantity"]),
1384
+ const invoice = asRecord3(asRecord3(providerPayload)?.["invoice"]);
1385
+ return asRecordList3(invoice?.["invoice_lines_attributes"]).map((line) => ({
1386
+ description: asString5(line["description"]),
1387
+ quantity: asNullableNumber4(line["quantity"]),
1065
1388
  price: asMoney2(line["price"]),
1066
- unit: asNullableNumber2(line["unit"]),
1067
- taxes: asRecordList(line["taxes_attributes"]).map((tax) => ({
1068
- name: asString3(tax["name"]),
1069
- percent: asNullableNumber2(tax["percent"]),
1070
- category: asNullableString3(tax["category"]),
1071
- comment: asNullableString3(tax["comment"])
1389
+ unit: asNullableNumber4(line["unit"]),
1390
+ taxes: asRecordList3(line["taxes_attributes"]).map((tax) => ({
1391
+ name: asString5(tax["name"]),
1392
+ percent: asNullableNumber4(tax["percent"]),
1393
+ category: asNullableString5(tax["category"]),
1394
+ comment: asNullableString5(tax["comment"])
1072
1395
  }))
1073
1396
  }));
1074
1397
  }
1075
1398
  var ComplianceTransaction = class _ComplianceTransaction {
1076
- constructor(id, companyId, complianceEnrollmentId, country, regime, transactionType, transactionTypeLabel, state, stateLabel, invoiceNumber, invoiceDate, dueDate, currency, subtotal, taxAmount, total, counterpartyName, counterpartyCountry, counterpartyVatNumber, isPaid, paidAt, providerInvoiceId, submissionError, reportedAt, taxReport, createdAt, updatedAt, counterpartyRegisterId = null, counterpartyAddress = null, counterpartyCity = null, counterpartyPostalcode = null, counterpartyEmail = null, buyerReference = null, documentType = ComplianceDocumentType.INVOICE, amendedNumber = null, amendedDate = null, providerState = null, invoiceLines = []) {
1399
+ constructor(id, companyId, complianceEnrollmentId, country, regime, transactionType, transactionTypeLabel, state, stateLabel, invoiceNumber, invoiceDate, dueDate, currency, subtotal, taxAmount, total, counterpartyName, counterpartyCountry, counterpartyVatNumber, isPaid, paidAt, providerInvoiceId, submissionError, reportedAt, taxReport, createdAt, updatedAt, counterpartyRegisterId = null, counterpartyAddress = null, counterpartyCity = null, counterpartyPostalcode = null, counterpartyEmail = null, buyerReference = null, documentType = ComplianceDocumentType.INVOICE, amendedNumber = null, amendedDate = null, providerState = null, invoiceLines = [], documentUrl = null, deliveryCheck = null, invoicePdf = null, internalReference = null, pdfUrl = null, buyerRejected = false, rejectionReason = null, eurEquivalent = null) {
1077
1400
  this.id = id;
1078
1401
  this.companyId = companyId;
1079
1402
  this.complianceEnrollmentId = complianceEnrollmentId;
@@ -1112,6 +1435,14 @@ var ComplianceTransaction = class _ComplianceTransaction {
1112
1435
  this.amendedDate = amendedDate;
1113
1436
  this.providerState = providerState;
1114
1437
  this.invoiceLines = invoiceLines;
1438
+ this.documentUrl = documentUrl;
1439
+ this.deliveryCheck = deliveryCheck;
1440
+ this.invoicePdf = invoicePdf;
1441
+ this.internalReference = internalReference;
1442
+ this.pdfUrl = pdfUrl;
1443
+ this.buyerRejected = buyerRejected;
1444
+ this.rejectionReason = rejectionReason;
1445
+ this.eurEquivalent = eurEquivalent;
1115
1446
  }
1116
1447
  id;
1117
1448
  companyId;
@@ -1151,50 +1482,66 @@ var ComplianceTransaction = class _ComplianceTransaction {
1151
1482
  amendedDate;
1152
1483
  providerState;
1153
1484
  invoiceLines;
1485
+ documentUrl;
1486
+ deliveryCheck;
1487
+ invoicePdf;
1488
+ internalReference;
1489
+ pdfUrl;
1490
+ buyerRejected;
1491
+ rejectionReason;
1492
+ eurEquivalent;
1154
1493
  get isCreditNote() {
1155
1494
  return this.documentType === ComplianceDocumentType.CREDIT_NOTE;
1156
1495
  }
1157
1496
  static fromArray(data) {
1158
1497
  const taxReport = typeof data["tax_report"] === "object" && data["tax_report"] !== null && !Array.isArray(data["tax_report"]) ? ComplianceTaxReport.fromArray(data["tax_report"]) : void 0;
1159
1498
  return new _ComplianceTransaction(
1160
- asNumber3(data["id"]),
1161
- asNumber3(data["company_id"]),
1162
- asNumber3(data["compliance_enrollment_id"]),
1163
- asString3(data["country"]),
1164
- asString3(data["regime"]),
1499
+ asNumber4(data["id"]),
1500
+ asNumber4(data["company_id"]),
1501
+ asNumber4(data["compliance_enrollment_id"]),
1502
+ asString5(data["country"]),
1503
+ asString5(data["regime"]),
1165
1504
  toComplianceTransactionType(data["transaction_type"]),
1166
- asString3(data["transaction_type_label"]),
1505
+ asString5(data["transaction_type_label"]),
1167
1506
  toComplianceTransactionState(data["state"]),
1168
- asString3(data["state_label"]),
1169
- asString3(data["invoice_number"]),
1170
- asNullableString3(data["invoice_date"]),
1171
- asNullableString3(data["due_date"]),
1172
- asString3(data["currency"], "EUR"),
1507
+ asString5(data["state_label"]),
1508
+ asString5(data["invoice_number"]),
1509
+ asNullableString5(data["invoice_date"]),
1510
+ asNullableString5(data["due_date"]),
1511
+ asString5(data["currency"], "EUR"),
1173
1512
  asMoney2(data["subtotal"]),
1174
1513
  asMoney2(data["tax_amount"]),
1175
1514
  asMoney2(data["total"]),
1176
- asNullableString3(data["counterparty_name"]),
1177
- asNullableString3(data["counterparty_country"]),
1178
- asNullableString3(data["counterparty_vat_number"]),
1515
+ asNullableString5(data["counterparty_name"]),
1516
+ asNullableString5(data["counterparty_country"]),
1517
+ asNullableString5(data["counterparty_vat_number"]),
1179
1518
  data["is_paid"] === true,
1180
- asNullableString3(data["paid_at"]),
1181
- asNullableString3(data["provider_invoice_id"]),
1182
- asNullableString3(data["submission_error"]),
1183
- asNullableString3(data["reported_at"]),
1519
+ asNullableString5(data["paid_at"]),
1520
+ asNullableString5(data["provider_invoice_id"]),
1521
+ asNullableString5(data["submission_error"]),
1522
+ asNullableString5(data["reported_at"]),
1184
1523
  taxReport,
1185
- asNullableString3(data["created_at"]),
1186
- asNullableString3(data["updated_at"]),
1187
- asNullableString3(data["counterparty_register_id"]),
1188
- asNullableString3(data["counterparty_address"]),
1189
- asNullableString3(data["counterparty_city"]),
1190
- asNullableString3(data["counterparty_postalcode"]),
1191
- asNullableString3(data["counterparty_email"]),
1192
- asNullableString3(data["buyer_reference"]),
1524
+ asNullableString5(data["created_at"]),
1525
+ asNullableString5(data["updated_at"]),
1526
+ asNullableString5(data["counterparty_register_id"]),
1527
+ asNullableString5(data["counterparty_address"]),
1528
+ asNullableString5(data["counterparty_city"]),
1529
+ asNullableString5(data["counterparty_postalcode"]),
1530
+ asNullableString5(data["counterparty_email"]),
1531
+ asNullableString5(data["buyer_reference"]),
1193
1532
  data["document_type"] === void 0 || data["document_type"] === null ? ComplianceDocumentType.INVOICE : toComplianceDocumentType(data["document_type"]),
1194
- asNullableString3(data["amended_number"]),
1195
- asNullableString3(data["amended_date"]),
1196
- asNullableString3(data["provider_state"]),
1197
- toInvoiceLines(data["provider_payload"])
1533
+ asNullableString5(data["amended_number"]),
1534
+ asNullableString5(data["amended_date"]),
1535
+ asNullableString5(data["provider_state"]),
1536
+ toInvoiceLines(data["provider_payload"]),
1537
+ asNullableString5(data["document_url"]),
1538
+ asRecord3(data["delivery_check"]),
1539
+ toInvoicePdf(data["invoice_pdf"]),
1540
+ asNullableString5(data["internal_reference"]),
1541
+ asNullableString5(data["pdf_url"]),
1542
+ data["buyer_rejected"] === true,
1543
+ asNullableString5(data["rejection_reason"]),
1544
+ toEurEquivalent(data["eur_equivalent"])
1198
1545
  );
1199
1546
  }
1200
1547
  };
@@ -1281,10 +1628,10 @@ function describePeppolLookupStatus(status) {
1281
1628
  }
1282
1629
 
1283
1630
  // src/dto/PeppolLookupResult.ts
1284
- function asString4(value, fallback = "") {
1631
+ function asString6(value, fallback = "") {
1285
1632
  return typeof value === "string" ? value : fallback;
1286
1633
  }
1287
- function asNullableString4(value) {
1634
+ function asNullableString6(value) {
1288
1635
  return typeof value === "string" ? value : null;
1289
1636
  }
1290
1637
  var PeppolLookupResult = class _PeppolLookupResult {
@@ -1315,21 +1662,21 @@ var PeppolLookupResult = class _PeppolLookupResult {
1315
1662
  return new _PeppolLookupResult(
1316
1663
  toPeppolLookupStatus(data["status"]),
1317
1664
  typeof data["reachable"] === "boolean" ? data["reachable"] : null,
1318
- asString4(data["country"]),
1319
- asString4(data["scheme"]),
1320
- asString4(data["id"]),
1665
+ asString6(data["country"]),
1666
+ asString6(data["scheme"]),
1667
+ asString6(data["id"]),
1321
1668
  documentTypes,
1322
- asNullableString4(data["transport_type_code"]),
1323
- asNullableString4(data["checked_at"])
1669
+ asNullableString6(data["transport_type_code"]),
1670
+ asNullableString6(data["checked_at"])
1324
1671
  );
1325
1672
  }
1326
1673
  };
1327
1674
 
1328
1675
  // src/dto/RegistryCompany.ts
1329
- function asString5(value, fallback = "") {
1676
+ function asString7(value, fallback = "") {
1330
1677
  return typeof value === "string" ? value : fallback;
1331
1678
  }
1332
- function asNullableString5(value) {
1679
+ function asNullableString7(value) {
1333
1680
  return typeof value === "string" ? value : null;
1334
1681
  }
1335
1682
  var RegistryCompany = class _RegistryCompany {
@@ -1361,27 +1708,27 @@ var RegistryCompany = class _RegistryCompany {
1361
1708
  country;
1362
1709
  static fromArray(data) {
1363
1710
  return new _RegistryCompany(
1364
- asString5(data["org_number"]),
1365
- asString5(data["company_name"]),
1366
- asNullableString5(data["organisation_form"]),
1711
+ asString7(data["org_number"]),
1712
+ asString7(data["company_name"]),
1713
+ asNullableString7(data["organisation_form"]),
1367
1714
  data["vat_registered"] === true,
1368
- asNullableString5(data["vat_number"]),
1715
+ asNullableString7(data["vat_number"]),
1369
1716
  data["enterprise_register"] === true,
1370
1717
  data["bankrupt"] === true,
1371
1718
  data["under_liquidation"] === true,
1372
- asNullableString5(data["address"]),
1373
- asNullableString5(data["postalcode"]),
1374
- asNullableString5(data["city"]),
1375
- asString5(data["country"])
1719
+ asNullableString7(data["address"]),
1720
+ asNullableString7(data["postalcode"]),
1721
+ asNullableString7(data["city"]),
1722
+ asString7(data["country"])
1376
1723
  );
1377
1724
  }
1378
1725
  };
1379
1726
 
1380
1727
  // src/dto/RevenueStatistics.ts
1381
- function asString6(value, fallback = "") {
1728
+ function asString8(value, fallback = "") {
1382
1729
  return typeof value === "string" ? value : fallback;
1383
1730
  }
1384
- function asNumber4(value) {
1731
+ function asNumber5(value) {
1385
1732
  return typeof value === "number" ? value : Number(value ?? 0) || 0;
1386
1733
  }
1387
1734
  function asMoney3(value) {
@@ -1393,7 +1740,7 @@ function asRecords(value) {
1393
1740
  }
1394
1741
  function toTotals(data) {
1395
1742
  return {
1396
- count: asNumber4(data["count"]),
1743
+ count: asNumber5(data["count"]),
1397
1744
  subtotal: asMoney3(data["subtotal"]),
1398
1745
  taxAmount: asMoney3(data["tax_amount"]),
1399
1746
  total: asMoney3(data["total"])
@@ -1430,35 +1777,35 @@ var RevenueStatistics = class _RevenueStatistics {
1430
1777
  typeof data["totals"] === "object" && data["totals"] !== null ? data["totals"] : {}
1431
1778
  );
1432
1779
  const timeSeries = asRecords(data["time_series"]).map((row) => ({
1433
- bucket: asString6(row["bucket"]),
1780
+ bucket: asString8(row["bucket"]),
1434
1781
  ...toTotals(row)
1435
1782
  }));
1436
1783
  const byType = asRecords(data["by_type"]).map((row) => ({
1437
- type: asString6(row["type"]),
1438
- typeLabel: asString6(row["type_label"]),
1439
- count: asNumber4(row["count"]),
1784
+ type: asString8(row["type"]),
1785
+ typeLabel: asString8(row["type_label"]),
1786
+ count: asNumber5(row["count"]),
1440
1787
  total: asMoney3(row["total"])
1441
1788
  }));
1442
1789
  const byCountry = asRecords(data["by_country"]).map((row) => ({
1443
- country: asString6(row["country"], "unknown"),
1444
- count: asNumber4(row["count"]),
1790
+ country: asString8(row["country"], "unknown"),
1791
+ count: asNumber5(row["count"]),
1445
1792
  total: asMoney3(row["total"])
1446
1793
  }));
1447
1794
  const byState = asRecords(data["by_state"]).map((row) => ({
1448
- state: asString6(row["state"]),
1449
- stateLabel: asString6(row["state_label"]),
1450
- count: asNumber4(row["count"]),
1795
+ state: asString8(row["state"]),
1796
+ stateLabel: asString8(row["state_label"]),
1797
+ count: asNumber5(row["count"]),
1451
1798
  total: asMoney3(row["total"])
1452
1799
  }));
1453
1800
  const byCurrency = asRecords(data["by_currency"]).map((row) => ({
1454
- currency: asString6(row["currency"]),
1801
+ currency: asString8(row["currency"]),
1455
1802
  ...toTotals(row)
1456
1803
  }));
1457
1804
  return new _RevenueStatistics(
1458
- asString6(range["date_from"]) || void 0,
1459
- asString6(range["date_to"]) || void 0,
1460
- asString6(range["interval"]) || void 0,
1461
- asString6(data["primary_currency"], "EUR"),
1805
+ asString8(range["date_from"]) || void 0,
1806
+ asString8(range["date_to"]) || void 0,
1807
+ asString8(range["interval"]) || void 0,
1808
+ asString8(data["primary_currency"], "EUR"),
1462
1809
  data["is_multi_currency"] === true,
1463
1810
  totals,
1464
1811
  timeSeries,
@@ -1471,10 +1818,10 @@ var RevenueStatistics = class _RevenueStatistics {
1471
1818
  };
1472
1819
 
1473
1820
  // src/dto/SireneLookupResult.ts
1474
- function asString7(value, fallback = "") {
1821
+ function asString9(value, fallback = "") {
1475
1822
  return typeof value === "string" ? value : fallback;
1476
1823
  }
1477
- function asNullableString6(value) {
1824
+ function asNullableString8(value) {
1478
1825
  return typeof value === "string" ? value : null;
1479
1826
  }
1480
1827
  var SireneLookupResult = class _SireneLookupResult {
@@ -1500,24 +1847,24 @@ var SireneLookupResult = class _SireneLookupResult {
1500
1847
  postalcode;
1501
1848
  static fromArray(data) {
1502
1849
  return new _SireneLookupResult(
1503
- asString7(data["company_name"]),
1504
- asString7(data["siren"]),
1505
- asNullableString6(data["siret"]),
1506
- asNullableString6(data["naf_code"]),
1507
- asNullableString6(data["naf_full"]),
1508
- asNullableString6(data["enterprise_size"]),
1509
- asNullableString6(data["address"]),
1510
- asNullableString6(data["city"]),
1511
- asNullableString6(data["postalcode"])
1850
+ asString9(data["company_name"]),
1851
+ asString9(data["siren"]),
1852
+ asNullableString8(data["siret"]),
1853
+ asNullableString8(data["naf_code"]),
1854
+ asNullableString8(data["naf_full"]),
1855
+ asNullableString8(data["enterprise_size"]),
1856
+ asNullableString8(data["address"]),
1857
+ asNullableString8(data["city"]),
1858
+ asNullableString8(data["postalcode"])
1512
1859
  );
1513
1860
  }
1514
1861
  };
1515
1862
 
1516
1863
  // src/dto/VatRates.ts
1517
- function asString8(value, fallback = "") {
1864
+ function asString10(value, fallback = "") {
1518
1865
  return typeof value === "string" ? value : fallback;
1519
1866
  }
1520
- function asNumber5(value) {
1867
+ function asNumber6(value) {
1521
1868
  return typeof value === "number" ? value : Number(value ?? 0) || 0;
1522
1869
  }
1523
1870
  var VatRates = class _VatRates {
@@ -1531,13 +1878,13 @@ var VatRates = class _VatRates {
1531
1878
  rates;
1532
1879
  static fromArray(data) {
1533
1880
  const rates = (Array.isArray(data["rates"]) ? data["rates"] : []).filter((row) => typeof row === "object" && row !== null).map((row) => ({
1534
- percent: asNumber5(row["percent"]),
1535
- category: asString8(row["category"]),
1536
- labelKey: asString8(row["label_key"]),
1537
- taxName: asString8(row["tax_name"]),
1881
+ percent: asNumber6(row["percent"]),
1882
+ category: asString10(row["category"]),
1883
+ labelKey: asString10(row["label_key"]),
1884
+ taxName: asString10(row["tax_name"]),
1538
1885
  requiresVatex: row["requires_vatex"] === true
1539
1886
  }));
1540
- return new _VatRates(asString8(data["country"]), asString8(data["currency"], "EUR"), rates);
1887
+ return new _VatRates(asString10(data["country"]), asString10(data["currency"], "EUR"), rates);
1541
1888
  }
1542
1889
  };
1543
1890
 
@@ -1596,10 +1943,15 @@ var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
1596
1943
  var NAF_CODE_REGEX = /^\d{2}$/;
1597
1944
  var COUNTRY_REGEX = /^[A-Za-z]{2}$/;
1598
1945
  var PEPPOL_SCHEME_REGEX = /^\d{4}$/;
1946
+ var INVOICE_PDF_MAX_BYTES = 10 * 1024 * 1024;
1947
+ var INVOICE_PDF_MAGIC = [37, 80, 68, 70, 45];
1599
1948
  var INTERVALS = ["day", "week", "month"];
1600
1949
  var SERVICES = ["e_reporting", "e_invoicing"];
1601
1950
  var ENTERPRISE_SIZES = ["micro", "pme", "eti", "ge"];
1602
1951
  var TYPE_OPERATIONS = ["services", "goods", "mixed"];
1952
+ var NOTIFICATION_LANGUAGES = ["de", "en"];
1953
+ var NOTIFICATION_DIGESTS = ["off", "daily", "weekly"];
1954
+ var NOTIFICATION_MAX_RECIPIENTS = 5;
1603
1955
  var TRANSACTION_TYPES = [
1604
1956
  "b2c_outbound",
1605
1957
  "b2b_domestic_outbound",
@@ -1794,6 +2146,8 @@ var EReportingEndpoint = class {
1794
2146
  this.validateInvoiceLines(input.invoiceLines);
1795
2147
  this.validateOptionalCodes(input);
1796
2148
  this.validateBuyerFields(input);
2149
+ this.validateInternalReference(input.internalReference);
2150
+ this.validateInvoicePdfFilename(input);
1797
2151
  const body = {
1798
2152
  compliance_enrollment_id: input.complianceEnrollmentId,
1799
2153
  transaction_type: input.transactionType,
@@ -1809,23 +2163,9 @@ var EReportingEndpoint = class {
1809
2163
  const data = await this.parseJsonResponse(response);
1810
2164
  return ComplianceTransaction.fromArray(data);
1811
2165
  }
1812
- /** Paginated list of the company's transactions (newest invoice date first), filterable by date / state / type / enrollment / country. */
2166
+ /** Paginated list of the company's transactions (newest invoice date first), filterable by date / state / type / enrollment / country / search / internal reference / provider state. */
1813
2167
  async listTransactions(filters = {}) {
1814
- if (filters.complianceEnrollmentId !== void 0) {
1815
- this.validateId(filters.complianceEnrollmentId, "complianceEnrollmentId");
1816
- }
1817
- if (filters.country !== void 0 && !COUNTRY_REGEX.test(filters.country)) {
1818
- throw new TaxoraException("country must be a 2-character ISO 3166-1 alpha-2 code.");
1819
- }
1820
- const params = new URLSearchParams();
1821
- if (filters.dateFrom !== void 0) params.set("date_from", this.formatDate(filters.dateFrom));
1822
- if (filters.dateTo !== void 0) params.set("date_to", this.formatDate(filters.dateTo));
1823
- if (filters.state !== void 0) params.set("state", filters.state);
1824
- if (filters.transactionType !== void 0) params.set("transaction_type", filters.transactionType);
1825
- if (filters.complianceEnrollmentId !== void 0) {
1826
- params.set("compliance_enrollment_id", String(filters.complianceEnrollmentId));
1827
- }
1828
- if (filters.country !== void 0) params.set("country", filters.country.toUpperCase());
2168
+ const params = this.buildTransactionFilterParams(filters);
1829
2169
  if (filters.page !== void 0) params.set("page", String(filters.page));
1830
2170
  if (filters.perPage !== void 0) params.set("per_page", String(filters.perPage));
1831
2171
  const queryString = params.toString();
@@ -1833,6 +2173,27 @@ var EReportingEndpoint = class {
1833
2173
  const response = await this.sendRequest("GET", url);
1834
2174
  return ComplianceTransactionPage.fromResponse(await this.parseJsonResponse(response));
1835
2175
  }
2176
+ /**
2177
+ * All transactions matching the filters as raw CSV for bookkeeping
2178
+ * (semicolon-separated) — the same filters as listTransactions() without
2179
+ * pagination. Columns: invoice_number, internal_reference, invoice_date,
2180
+ * due_date, country, transaction_type, document_type, state, delivery_state,
2181
+ * buyer_rejected, rejection_reason, counterparty_name, counterparty_country,
2182
+ * counterparty_vat_number, currency, subtotal, tax_amount, total, eur_rate,
2183
+ * eur_rate_date, eur_subtotal, eur_tax_amount, eur_total, provider_invoice_id,
2184
+ * created_at. The eur_* columns hold the ECB reference conversion for non-EUR
2185
+ * invoices (empty for EUR). Max 50,000 rows server-side. The body is returned
2186
+ * verbatim, a UTF-8 BOM included when the API sends one.
2187
+ */
2188
+ async exportTransactionsCsv(filters = {}) {
2189
+ const queryString = this.buildTransactionFilterParams(filters).toString();
2190
+ const url = `${this.baseUrl}/compliance/transactions/export.csv${queryString ? `?${queryString}` : ""}`;
2191
+ const response = await this.sendDownloadRequest(url, "text/csv, application/json");
2192
+ if (!response.ok) {
2193
+ await this.parseJsonResponse(response);
2194
+ }
2195
+ return new TextDecoder("utf-8", { ignoreBOM: true }).decode(await response.arrayBuffer());
2196
+ }
1836
2197
  /** Get a single transaction by id (includes its tax report when one exists). */
1837
2198
  async getTransaction(id) {
1838
2199
  this.validateId(id, "id");
@@ -1848,6 +2209,8 @@ var EReportingEndpoint = class {
1848
2209
  if (input.invoiceLines !== void 0) this.validateInvoiceLines(input.invoiceLines);
1849
2210
  this.validateOptionalCodes(input);
1850
2211
  this.validateBuyerFields(input);
2212
+ this.validateInternalReference(input.internalReference);
2213
+ this.validateInvoicePdfFilename(input);
1851
2214
  const body = {};
1852
2215
  if (input.transactionType !== void 0) body["transaction_type"] = input.transactionType;
1853
2216
  if (input.invoiceNumber !== void 0) body["invoice_number"] = input.invoiceNumber;
@@ -1882,6 +2245,47 @@ var EReportingEndpoint = class {
1882
2245
  const data = await this.parseJsonResponse(response);
1883
2246
  return ComplianceTransaction.fromArray(data);
1884
2247
  }
2248
+ /**
2249
+ * Download the legal e-invoice document of a sent transaction (e-invoicing,
2250
+ * e.g. the EHF/UBL XML for Norway). Available once `documentUrl` on the
2251
+ * transaction is set.
2252
+ *
2253
+ * Errors: 404 (HttpException) for an unknown transaction; 409 (HttpException)
2254
+ * when no document exists (yet) — e.g. e-reporting, not sent, or the network
2255
+ * has not produced it yet (try again in a few minutes); 502 on provider failure.
2256
+ */
2257
+ async getTransactionDocument(id) {
2258
+ this.validateId(id, "id");
2259
+ const response = await this.sendDownloadRequest(`${this.baseUrl}/compliance/transactions/${id}/document`, "*/*");
2260
+ if (!response.ok) {
2261
+ await this.parseJsonResponse(response);
2262
+ }
2263
+ return {
2264
+ content: new Uint8Array(await response.arrayBuffer()),
2265
+ contentType: response.headers.get("content-type") ?? "application/octet-stream",
2266
+ filename: this.filenameFromDisposition(response.headers.get("content-disposition"))
2267
+ };
2268
+ }
2269
+ /**
2270
+ * Download the invoice as a readable PDF — the seller's attached PDF, or the
2271
+ * provider's rendering of the e-invoice. Available once `pdfUrl` on the
2272
+ * transaction is set.
2273
+ *
2274
+ * Errors: 404 (HttpException) for an unknown transaction; 409 (HttpException)
2275
+ * when no PDF exists (yet); 502 on provider failure.
2276
+ */
2277
+ async getTransactionPdf(id) {
2278
+ this.validateId(id, "id");
2279
+ const response = await this.sendDownloadRequest(`${this.baseUrl}/compliance/transactions/${id}/pdf`, "*/*");
2280
+ if (!response.ok) {
2281
+ await this.parseJsonResponse(response);
2282
+ }
2283
+ return {
2284
+ content: new Uint8Array(await response.arrayBuffer()),
2285
+ contentType: response.headers.get("content-type") ?? "application/octet-stream",
2286
+ filename: this.filenameFromDisposition(response.headers.get("content-disposition"))
2287
+ };
2288
+ }
1885
2289
  /**
1886
2290
  * Bulk-import transactions from a semicolon-separated CSV (one row per invoice
1887
2291
  * line; rows sharing an invoice_number are grouped into one transaction).
@@ -1913,6 +2317,9 @@ var EReportingEndpoint = class {
1913
2317
  * months and a monthly interval.
1914
2318
  */
1915
2319
  async getRevenueStatistics(filters = {}) {
2320
+ if (filters.complianceEnrollmentId !== void 0) {
2321
+ this.validateId(filters.complianceEnrollmentId, "complianceEnrollmentId");
2322
+ }
1916
2323
  if (filters.interval !== void 0 && !INTERVALS.includes(filters.interval)) {
1917
2324
  throw new TaxoraException(
1918
2325
  `Invalid statistics interval "${String(filters.interval)}". Expected one of: ${INTERVALS.join(", ")}.`
@@ -1924,12 +2331,42 @@ var EReportingEndpoint = class {
1924
2331
  if (filters.interval !== void 0) params.set("interval", filters.interval);
1925
2332
  if (filters.transactionType !== void 0) params.set("transaction_type", filters.transactionType);
1926
2333
  if (filters.state !== void 0) params.set("state", filters.state);
2334
+ if (filters.complianceEnrollmentId !== void 0) {
2335
+ params.set("compliance_enrollment_id", String(filters.complianceEnrollmentId));
2336
+ }
1927
2337
  const queryString = params.toString();
1928
2338
  const url = `${this.baseUrl}/compliance/revenue-statistics${queryString ? `?${queryString}` : ""}`;
1929
2339
  const response = await this.sendRequest("GET", url);
1930
2340
  const data = await this.parseJsonResponse(response);
1931
2341
  return RevenueStatistics.fromArray(data);
1932
2342
  }
2343
+ /**
2344
+ * Net and VAT per month, currency and tax rate as raw CSV (semicolon-separated,
2345
+ * computed from the invoice lines) — for reconciling the reported figures with
2346
+ * your VAT return. Same filters as getRevenueStatistics() (without
2347
+ * `interval`); defaults to the last 12 months. The body is returned verbatim,
2348
+ * a UTF-8 BOM included when the API sends one.
2349
+ */
2350
+ async exportRevenueTaxRatesCsv(filters = {}) {
2351
+ if (filters.complianceEnrollmentId !== void 0) {
2352
+ this.validateId(filters.complianceEnrollmentId, "complianceEnrollmentId");
2353
+ }
2354
+ const params = new URLSearchParams();
2355
+ if (filters.dateFrom !== void 0) params.set("date_from", this.formatDate(filters.dateFrom));
2356
+ if (filters.dateTo !== void 0) params.set("date_to", this.formatDate(filters.dateTo));
2357
+ if (filters.transactionType !== void 0) params.set("transaction_type", filters.transactionType);
2358
+ if (filters.state !== void 0) params.set("state", filters.state);
2359
+ if (filters.complianceEnrollmentId !== void 0) {
2360
+ params.set("compliance_enrollment_id", String(filters.complianceEnrollmentId));
2361
+ }
2362
+ const queryString = params.toString();
2363
+ const url = `${this.baseUrl}/compliance/revenue-statistics/tax-rates.csv${queryString ? `?${queryString}` : ""}`;
2364
+ const response = await this.sendDownloadRequest(url, "text/csv, application/json");
2365
+ if (!response.ok) {
2366
+ await this.parseJsonResponse(response);
2367
+ }
2368
+ return new TextDecoder("utf-8", { ignoreBOM: true }).decode(await response.arrayBuffer());
2369
+ }
1933
2370
  /**
1934
2371
  * The canonical VAT rates & DGFiP tax categories for a reporting country
1935
2372
  * (the seller's reporting-country rates, not the counterparty's). Falls back
@@ -1944,12 +2381,19 @@ var EReportingEndpoint = class {
1944
2381
  const data = await this.parseJsonResponse(response);
1945
2382
  return VatRates.fromArray(data);
1946
2383
  }
1947
- /** Paginated list of the company's tax reports (newest first), optionally filtered by state. */
1948
- async listTaxReports(page = 1, perPage = 25, state) {
2384
+ /**
2385
+ * Paginated list of the company's tax reports (newest first), optionally
2386
+ * filtered by state and by country (2-letter ISO code, case-insensitive).
2387
+ */
2388
+ async listTaxReports(page = 1, perPage = 25, state, country) {
2389
+ if (country !== void 0 && !COUNTRY_REGEX.test(country)) {
2390
+ throw new TaxoraException("country must be a 2-character ISO 3166-1 alpha-2 code.");
2391
+ }
1949
2392
  const params = new URLSearchParams();
1950
2393
  params.set("page", String(page));
1951
2394
  params.set("per_page", String(perPage));
1952
2395
  if (state !== void 0) params.set("state", state);
2396
+ if (country !== void 0) params.set("country", country.toUpperCase());
1953
2397
  const response = await this.sendRequest("GET", `${this.baseUrl}/compliance/tax-reports?${params.toString()}`);
1954
2398
  return ComplianceTaxReportPage.fromResponse(await this.parseJsonResponse(response));
1955
2399
  }
@@ -1991,8 +2435,177 @@ var EReportingEndpoint = class {
1991
2435
  await this.parseJsonResponse(response);
1992
2436
  }
1993
2437
  // ---------------------------------------------------------------------
2438
+ // Self-service plans (Stripe) — not gated by compliance access
2439
+ // ---------------------------------------------------------------------
2440
+ /**
2441
+ * Bookable compliance plans per country (net EUR prices), every country
2442
+ * Taxora reaches, and which services the company has unlocked. Works for
2443
+ * companies without compliance access.
2444
+ */
2445
+ async getOfferings() {
2446
+ const response = await this.sendRequest("GET", `${this.baseUrl}/compliance/offerings`);
2447
+ return ComplianceOfferings.fromArray(await this.parseJsonResponse(response));
2448
+ }
2449
+ /**
2450
+ * Start a Stripe Checkout for a plan (see getOfferings() — `checkoutAvailable`).
2451
+ * Open the returned `url` in the browser. After payment Stripe redirects to
2452
+ * the Taxora portal, which activates the plan; call confirmCheckout() with the
2453
+ * session id to activate it from your side (idempotent).
2454
+ *
2455
+ * Errors: 422 (ValidationException) for an unknown or contact-only plan or a
2456
+ * plan that is already active; 502 (HttpException) on a Stripe error.
2457
+ */
2458
+ async createCheckout(country, plan) {
2459
+ if (!COUNTRY_REGEX.test(country)) {
2460
+ throw new TaxoraException("country must be a 2-character ISO 3166-1 alpha-2 code.");
2461
+ }
2462
+ if (plan.trim() === "" || plan.length > 30) {
2463
+ throw new TaxoraException("plan must be a non-empty plan key of at most 30 characters.");
2464
+ }
2465
+ const response = await this.sendRequest("POST", `${this.baseUrl}/compliance/checkout`, {
2466
+ country: country.toUpperCase(),
2467
+ plan
2468
+ });
2469
+ const data = await this.parseJsonResponse(response);
2470
+ return { id: String(data["id"] ?? ""), url: String(data["url"] ?? "") };
2471
+ }
2472
+ /** Confirm a finished Stripe Checkout and activate its plan. Idempotent. */
2473
+ async confirmCheckout(sessionId) {
2474
+ if (sessionId.trim() === "" || sessionId.length > 255) {
2475
+ throw new TaxoraException("sessionId must be a non-empty string of at most 255 characters.");
2476
+ }
2477
+ const response = await this.sendRequest("POST", `${this.baseUrl}/compliance/checkout/confirm`, {
2478
+ session_id: sessionId
2479
+ });
2480
+ const data = await this.parseJsonResponse(response);
2481
+ const str = (value) => typeof value === "string" ? value : null;
2482
+ return {
2483
+ active: data["active"] === true,
2484
+ country: str(data["country"]),
2485
+ service: str(data["service"]),
2486
+ plan: str(data["plan"]),
2487
+ status: str(data["status"])
2488
+ };
2489
+ }
2490
+ /**
2491
+ * URL of the Stripe billing portal for the company's compliance plans
2492
+ * (invoices, payment method, cancellation). The portal returns to the Taxora
2493
+ * portal. 404 (HttpException) when no plan was bought via Stripe.
2494
+ */
2495
+ async createBillingPortalSession() {
2496
+ const response = await this.sendRequest("POST", `${this.baseUrl}/compliance/billing-portal`);
2497
+ const data = await this.parseJsonResponse(response);
2498
+ return String(data["url"] ?? "");
2499
+ }
2500
+ // ---------------------------------------------------------------------
2501
+ // Notification emails
2502
+ // ---------------------------------------------------------------------
2503
+ /**
2504
+ * The company's opt-in e-reporting / e-invoicing emails: recipients, language,
2505
+ * the "buyer not on Peppol" email and the digest. Readable by every member.
2506
+ */
2507
+ async getNotificationSettings() {
2508
+ const response = await this.sendRequest("GET", `${this.baseUrl}/compliance/notification-settings`);
2509
+ return this.toNotificationSettings(await this.parseJsonResponse(response));
2510
+ }
2511
+ /**
2512
+ * Change the company's e-reporting / e-invoicing emails; only the provided
2513
+ * fields change. `notOnPeppol` only reports invoices held back after it was
2514
+ * switched on.
2515
+ *
2516
+ * Errors: 422 (ValidationException) when an email is switched on without any
2517
+ * recipient; 403 (HttpException, body code `admin_only` or `read_only_role`)
2518
+ * for users who are not company admins.
2519
+ */
2520
+ async updateNotificationSettings(input) {
2521
+ const body = {};
2522
+ if (input.recipients !== void 0) {
2523
+ if (!Array.isArray(input.recipients)) {
2524
+ throw new TaxoraException("recipients must be an array of email addresses.");
2525
+ }
2526
+ if (input.recipients.length > NOTIFICATION_MAX_RECIPIENTS) {
2527
+ throw new TaxoraException(`recipients must not contain more than ${NOTIFICATION_MAX_RECIPIENTS} entries.`);
2528
+ }
2529
+ body["recipients"] = input.recipients.map((recipient, index) => {
2530
+ const email = typeof recipient === "string" ? recipient.trim() : recipient;
2531
+ this.validateEmail(email, `recipients[${index}]`);
2532
+ if (email.length > 191) {
2533
+ throw new TaxoraException(`recipients[${index}] must not exceed 191 characters.`);
2534
+ }
2535
+ return email;
2536
+ });
2537
+ }
2538
+ if (input.language !== void 0) {
2539
+ if (!NOTIFICATION_LANGUAGES.includes(input.language)) {
2540
+ throw new TaxoraException(
2541
+ `Invalid language "${String(input.language)}". Expected one of: ${NOTIFICATION_LANGUAGES.join(", ")}.`
2542
+ );
2543
+ }
2544
+ body["language"] = input.language;
2545
+ }
2546
+ if (input.notOnPeppol !== void 0) {
2547
+ if (typeof input.notOnPeppol !== "boolean") {
2548
+ throw new TaxoraException("notOnPeppol must be a boolean.");
2549
+ }
2550
+ body["not_on_peppol"] = input.notOnPeppol;
2551
+ }
2552
+ if (input.digest !== void 0) {
2553
+ if (!NOTIFICATION_DIGESTS.includes(input.digest)) {
2554
+ throw new TaxoraException(
2555
+ `Invalid digest "${String(input.digest)}". Expected one of: ${NOTIFICATION_DIGESTS.join(", ")}.`
2556
+ );
2557
+ }
2558
+ body["digest"] = input.digest;
2559
+ }
2560
+ if (Object.keys(body).length === 0) {
2561
+ throw new TaxoraException("updateNotificationSettings requires at least one field to update.");
2562
+ }
2563
+ const response = await this.sendRequest("PUT", `${this.baseUrl}/compliance/notification-settings`, body);
2564
+ return this.toNotificationSettings(await this.parseJsonResponse(response));
2565
+ }
2566
+ toNotificationSettings(data) {
2567
+ const recipients = Array.isArray(data["recipients"]) ? data["recipients"].filter((r) => typeof r === "string" && r !== "") : [];
2568
+ const digest = data["digest"];
2569
+ return {
2570
+ recipients,
2571
+ language: data["language"] === "en" ? "en" : "de",
2572
+ notOnPeppol: data["not_on_peppol"] === true,
2573
+ digest: digest === "daily" || digest === "weekly" ? digest : "off",
2574
+ digestSentAt: typeof data["digest_sent_at"] === "string" ? data["digest_sent_at"] : null
2575
+ };
2576
+ }
2577
+ // ---------------------------------------------------------------------
1994
2578
  // Input validation (fail fast, before any request is sent)
1995
2579
  // ---------------------------------------------------------------------
2580
+ /** Validated transaction-list filters as query params (shared by listTransactions and exportTransactionsCsv). */
2581
+ buildTransactionFilterParams(filters) {
2582
+ if (filters.complianceEnrollmentId !== void 0) {
2583
+ this.validateId(filters.complianceEnrollmentId, "complianceEnrollmentId");
2584
+ }
2585
+ if (filters.country !== void 0 && !COUNTRY_REGEX.test(filters.country)) {
2586
+ throw new TaxoraException("country must be a 2-character ISO 3166-1 alpha-2 code.");
2587
+ }
2588
+ if (filters.search !== void 0 && filters.search.length > 100) {
2589
+ throw new TaxoraException("search must not exceed 100 characters.");
2590
+ }
2591
+ this.validateInternalReference(filters.internalReference);
2592
+ if (filters.providerState !== void 0 && !/^[a-z_]{1,30}$/.test(filters.providerState)) {
2593
+ throw new TaxoraException('providerState must be 1-30 lowercase letters or underscores (e.g. "refused").');
2594
+ }
2595
+ const params = new URLSearchParams();
2596
+ if (filters.dateFrom !== void 0) params.set("date_from", this.formatDate(filters.dateFrom));
2597
+ if (filters.dateTo !== void 0) params.set("date_to", this.formatDate(filters.dateTo));
2598
+ if (filters.state !== void 0) params.set("state", filters.state);
2599
+ if (filters.transactionType !== void 0) params.set("transaction_type", filters.transactionType);
2600
+ if (filters.complianceEnrollmentId !== void 0) {
2601
+ params.set("compliance_enrollment_id", String(filters.complianceEnrollmentId));
2602
+ }
2603
+ if (filters.country !== void 0) params.set("country", filters.country.toUpperCase());
2604
+ if (filters.search !== void 0) params.set("search", filters.search);
2605
+ if (filters.internalReference !== void 0) params.set("internal_reference", filters.internalReference);
2606
+ if (filters.providerState !== void 0) params.set("provider_state", filters.providerState);
2607
+ return params;
2608
+ }
1996
2609
  validateEnrollmentInput(input) {
1997
2610
  if (input.siret === void 0 && input.siren === void 0) {
1998
2611
  throw new TaxoraException("Either siret or siren is required.");
@@ -2120,6 +2733,20 @@ var EReportingEndpoint = class {
2120
2733
  }
2121
2734
  });
2122
2735
  }
2736
+ validateInvoicePdfFilename(input) {
2737
+ if (input.invoicePdfFilename === void 0) return;
2738
+ if (input.invoicePdfFilename.length > 120) {
2739
+ throw new TaxoraException("invoicePdfFilename must not exceed 120 characters.");
2740
+ }
2741
+ if (input.invoicePdf === void 0) {
2742
+ throw new TaxoraException("invoicePdfFilename requires invoicePdf.");
2743
+ }
2744
+ }
2745
+ validateInternalReference(internalReference) {
2746
+ if (internalReference !== void 0 && internalReference.length > 100) {
2747
+ throw new TaxoraException("internalReference must not exceed 100 characters.");
2748
+ }
2749
+ }
2123
2750
  validateOptionalCodes(input) {
2124
2751
  if (input.currency !== void 0 && input.currency.length !== 3) {
2125
2752
  throw new TaxoraException("currency must be a 3-character ISO 4217 code.");
@@ -2201,6 +2828,29 @@ var EReportingEndpoint = class {
2201
2828
  if (input.amendedNumber !== void 0) body["amended_number"] = input.amendedNumber;
2202
2829
  if (input.amendedDate !== void 0) body["amended_date"] = this.formatDate(input.amendedDate);
2203
2830
  if (input.extraInfo !== void 0) body["extra_info"] = input.extraInfo;
2831
+ if (input.internalReference !== void 0) body["internal_reference"] = input.internalReference;
2832
+ if (input.invoicePdf !== void 0) body["invoice_pdf"] = this.encodeInvoicePdf(input.invoicePdf);
2833
+ if (input.invoicePdfFilename !== void 0) body["invoice_pdf_filename"] = input.invoicePdfFilename;
2834
+ }
2835
+ /** Bytes → base64 (validated as a PDF of at most 10 MB); strings are taken as already base64. */
2836
+ encodeInvoicePdf(pdf) {
2837
+ if (typeof pdf === "string") {
2838
+ if (pdf.trim() === "") {
2839
+ throw new TaxoraException("invoicePdf must not be empty.");
2840
+ }
2841
+ return pdf;
2842
+ }
2843
+ const bytes = pdf instanceof Uint8Array ? pdf : new Uint8Array(pdf);
2844
+ if (bytes.byteLength === 0) {
2845
+ throw new TaxoraException("invoicePdf must not be empty.");
2846
+ }
2847
+ if (bytes.byteLength > INVOICE_PDF_MAX_BYTES) {
2848
+ throw new TaxoraException("invoicePdf must not exceed 10 MB.");
2849
+ }
2850
+ if (!INVOICE_PDF_MAGIC.every((byte, index) => bytes[index] === byte)) {
2851
+ throw new TaxoraException('invoicePdf must be a PDF file (content must start with "%PDF-").');
2852
+ }
2853
+ return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64");
2204
2854
  }
2205
2855
  // ---------------------------------------------------------------------
2206
2856
  // HTTP plumbing (kept in sync with SmartEnrichmentEndpoint)
@@ -2224,6 +2874,30 @@ var EReportingEndpoint = class {
2224
2874
  const send = () => this.httpClient.request(method, url, options);
2225
2875
  return method === "GET" ? withResponseRetries(this.retryPolicy, "e-reporting request", send) : send();
2226
2876
  }
2877
+ /** GET for a non-JSON download (CSV / document): no JSON Content-Type, retried like other GETs. */
2878
+ async sendDownloadRequest(url, accept) {
2879
+ const headers = this.buildHeaders(false);
2880
+ headers["Accept"] = accept;
2881
+ return withResponseRetries(
2882
+ this.retryPolicy,
2883
+ "e-reporting download",
2884
+ () => this.httpClient.request("GET", url, { headers })
2885
+ );
2886
+ }
2887
+ /** `attachment; filename="x.xml"` (or RFC 5987 `filename*=UTF-8''x.xml`) → "x.xml". */
2888
+ filenameFromDisposition(header) {
2889
+ if (header === null) return null;
2890
+ const extended = /filename\*\s*=\s*(?:UTF-8|utf-8)''([^;]+)/.exec(header);
2891
+ if (extended?.[1] !== void 0) {
2892
+ try {
2893
+ return decodeURIComponent(extended[1].trim());
2894
+ } catch {
2895
+ }
2896
+ }
2897
+ const plain = /filename\s*=\s*"([^"]*)"|filename\s*=\s*([^;]+)/.exec(header);
2898
+ const name = (plain?.[1] ?? plain?.[2])?.trim();
2899
+ return name !== void 0 && name !== "" ? name : null;
2900
+ }
2227
2901
  /** Multipart upload: Content-Type is left to fetch so the boundary is set correctly. */
2228
2902
  async sendMultipartRequest(method, url, form) {
2229
2903
  return this.httpClient.request(method, url, { headers: this.buildHeaders(false), body: form });
@@ -2318,6 +2992,73 @@ var EReportingEndpoint = class {
2318
2992
  }
2319
2993
  };
2320
2994
 
2995
+ // src/dto/SmartEnrichmentRecheck.ts
2996
+ var toIndexes = (value) => Array.isArray(value) ? value.filter((v) => typeof v === "number" && Number.isInteger(v)) : [];
2997
+ var SmartEnrichmentRecheck = class _SmartEnrichmentRecheck {
2998
+ constructor(jobId, rows, checks, skipped, dryRun) {
2999
+ this.jobId = jobId;
3000
+ this.rows = rows;
3001
+ this.checks = checks;
3002
+ this.skipped = skipped;
3003
+ this.dryRun = dryRun;
3004
+ }
3005
+ jobId;
3006
+ rows;
3007
+ checks;
3008
+ skipped;
3009
+ dryRun;
3010
+ static fromArray(data) {
3011
+ const skipped = {};
3012
+ const rawSkipped = data["skipped"];
3013
+ if (typeof rawSkipped === "object" && rawSkipped !== null && !Array.isArray(rawSkipped)) {
3014
+ for (const [reason, count] of Object.entries(rawSkipped)) {
3015
+ if (typeof count === "number") skipped[reason] = count;
3016
+ }
3017
+ }
3018
+ return new _SmartEnrichmentRecheck(
3019
+ typeof data["jobId"] === "string" ? data["jobId"] : "",
3020
+ toIndexes(data["rows"]),
3021
+ typeof data["checks"] === "number" ? data["checks"] : 0,
3022
+ skipped,
3023
+ data["dryRun"] === true
3024
+ );
3025
+ }
3026
+ };
3027
+ var SmartEnrichmentRecheckState = class _SmartEnrichmentRecheckState {
3028
+ constructor(eligible, runs, maxPerRow, cooldownDays) {
3029
+ this.eligible = eligible;
3030
+ this.runs = runs;
3031
+ this.maxPerRow = maxPerRow;
3032
+ this.cooldownDays = cooldownDays;
3033
+ }
3034
+ eligible;
3035
+ runs;
3036
+ maxPerRow;
3037
+ cooldownDays;
3038
+ static fromArray(data) {
3039
+ const runs = {};
3040
+ const rawRuns = data["runs"];
3041
+ if (typeof rawRuns === "object" && rawRuns !== null && !Array.isArray(rawRuns)) {
3042
+ for (const [index, run] of Object.entries(rawRuns)) {
3043
+ if (!/^\d+$/.test(index) || typeof run !== "object" || run === null) continue;
3044
+ const { state, resolved } = run;
3045
+ if (state !== "queued" && state !== "running" && state !== "finished" && state !== "failed") continue;
3046
+ runs[Number(index)] = typeof resolved === "boolean" ? { state, resolved } : { state };
3047
+ }
3048
+ }
3049
+ return new _SmartEnrichmentRecheckState(
3050
+ toIndexes(data["eligible"]),
3051
+ runs,
3052
+ typeof data["maxPerRow"] === "number" ? data["maxPerRow"] : 3,
3053
+ typeof data["cooldownDays"] === "number" ? data["cooldownDays"] : 7
3054
+ );
3055
+ }
3056
+ /** True while any recheck of this lookup is queued or running. */
3057
+ isActive() {
3058
+ return Object.values(this.runs).some((run) => run.state === "queued" || run.state === "running");
3059
+ }
3060
+ };
3061
+
2321
3062
  // src/enums/SmartEnrichmentMode.ts
2322
3063
  var SmartEnrichmentMode = {
2323
3064
  DEFAULT: "default",
@@ -2447,7 +3188,7 @@ function toOfficialAddress(value) {
2447
3188
  return Object.keys(address).length > 0 ? address : void 0;
2448
3189
  }
2449
3190
  var SmartEnrichmentResource = class _SmartEnrichmentResource {
2450
- constructor(status, vatNumber, vatType, confidence, matchedCompanyName, matchedAddress, country, source, mode = void 0, providerVerdicts = [], addressQuality = void 0, rejectedCandidates = [], sourceUrl = void 0, registeredOwner = void 0, sourceUrls = [], taxNumber = void 0, vatValid = void 0, aiScore = void 0, nameMatch = void 0, officialName = void 0, officialAddress = void 0, taxNumberType = void 0, taxNumberLabel = void 0, taxNumberSource = void 0) {
3191
+ constructor(status, vatNumber, vatType, confidence, matchedCompanyName, matchedAddress, country, source, mode = void 0, providerVerdicts = [], addressQuality = void 0, rejectedCandidates = [], sourceUrl = void 0, registeredOwner = void 0, sourceUrls = [], taxNumber = void 0, vatValid = void 0, aiScore = void 0, nameMatch = void 0, officialName = void 0, officialAddress = void 0, taxNumberType = void 0, taxNumberLabel = void 0, taxNumberSource = void 0, recheckCount = void 0, lastRecheckedAt = void 0) {
2451
3192
  this.status = status;
2452
3193
  this.vatNumber = vatNumber;
2453
3194
  this.vatType = vatType;
@@ -2472,6 +3213,8 @@ var SmartEnrichmentResource = class _SmartEnrichmentResource {
2472
3213
  this.taxNumberType = taxNumberType;
2473
3214
  this.taxNumberLabel = taxNumberLabel;
2474
3215
  this.taxNumberSource = taxNumberSource;
3216
+ this.recheckCount = recheckCount;
3217
+ this.lastRecheckedAt = lastRecheckedAt;
2475
3218
  }
2476
3219
  status;
2477
3220
  vatNumber;
@@ -2497,6 +3240,8 @@ var SmartEnrichmentResource = class _SmartEnrichmentResource {
2497
3240
  taxNumberType;
2498
3241
  taxNumberLabel;
2499
3242
  taxNumberSource;
3243
+ recheckCount;
3244
+ lastRecheckedAt;
2500
3245
  /** True when the register knows the number under a different name than the one requested. */
2501
3246
  nameMismatch() {
2502
3247
  return this.nameMatch === "mismatch";
@@ -2547,7 +3292,9 @@ var SmartEnrichmentResource = class _SmartEnrichmentResource {
2547
3292
  toOfficialAddress(data["officialAddress"]),
2548
3293
  text("taxNumberType"),
2549
3294
  text("taxNumberLabel"),
2550
- data["taxNumberSource"] === "vat_id" || data["taxNumberSource"] === "company_website" ? data["taxNumberSource"] : void 0
3295
+ data["taxNumberSource"] === "vat_id" || data["taxNumberSource"] === "company_website" ? data["taxNumberSource"] : void 0,
3296
+ num("recheckCount"),
3297
+ text("lastRecheckedAt")
2551
3298
  );
2552
3299
  }
2553
3300
  toArray() {
@@ -2575,20 +3322,23 @@ var SmartEnrichmentResource = class _SmartEnrichmentResource {
2575
3322
  officialAddress: this.officialAddress ?? null,
2576
3323
  taxNumberType: this.taxNumberType ?? null,
2577
3324
  taxNumberLabel: this.taxNumberLabel ?? null,
2578
- taxNumberSource: this.taxNumberSource ?? null
3325
+ taxNumberSource: this.taxNumberSource ?? null,
3326
+ recheckCount: this.recheckCount ?? null,
3327
+ lastRecheckedAt: this.lastRecheckedAt ?? null
2579
3328
  };
2580
3329
  }
2581
3330
  };
2582
3331
 
2583
3332
  // src/dto/SmartEnrichmentJob.ts
2584
3333
  var SmartEnrichmentJob = class _SmartEnrichmentJob {
2585
- constructor(jobId, status, itemCount, completedCount, foundCount, results) {
3334
+ constructor(jobId, status, itemCount, completedCount, foundCount, results, recheck = void 0) {
2586
3335
  this.jobId = jobId;
2587
3336
  this.status = status;
2588
3337
  this.itemCount = itemCount;
2589
3338
  this.completedCount = completedCount;
2590
3339
  this.foundCount = foundCount;
2591
3340
  this.results = results;
3341
+ this.recheck = recheck;
2592
3342
  }
2593
3343
  jobId;
2594
3344
  status;
@@ -2596,6 +3346,7 @@ var SmartEnrichmentJob = class _SmartEnrichmentJob {
2596
3346
  completedCount;
2597
3347
  foundCount;
2598
3348
  results;
3349
+ recheck;
2599
3350
  static fromArray(data) {
2600
3351
  const num = (key) => {
2601
3352
  const v = data[key];
@@ -2613,7 +3364,8 @@ var SmartEnrichmentJob = class _SmartEnrichmentJob {
2613
3364
  num("itemCount"),
2614
3365
  num("completedCount"),
2615
3366
  num("foundCount"),
2616
- results
3367
+ results,
3368
+ typeof data["recheck"] === "object" && data["recheck"] !== null && !Array.isArray(data["recheck"]) ? SmartEnrichmentRecheckState.fromArray(data["recheck"]) : void 0
2617
3369
  );
2618
3370
  }
2619
3371
  isProcessing() {
@@ -2727,13 +3479,13 @@ var SmartEnrichmentHistoryPage = class _SmartEnrichmentHistoryPage {
2727
3479
  };
2728
3480
 
2729
3481
  // src/dto/SmartEnrichmentStatistics.ts
2730
- function asString9(value, fallback = "") {
3482
+ function asString11(value, fallback = "") {
2731
3483
  return typeof value === "string" ? value : fallback;
2732
3484
  }
2733
- function asNumber6(value) {
3485
+ function asNumber7(value) {
2734
3486
  return typeof value === "number" ? value : Number(value ?? 0) || 0;
2735
3487
  }
2736
- function asRecord2(value) {
3488
+ function asRecord4(value) {
2737
3489
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
2738
3490
  }
2739
3491
  function asRecords2(value) {
@@ -2756,39 +3508,39 @@ var SmartEnrichmentStatistics = class _SmartEnrichmentStatistics {
2756
3508
  byOutcome;
2757
3509
  confidenceBuckets;
2758
3510
  static fromArray(data) {
2759
- const range = asRecord2(data["range"]);
2760
- const totals = asRecord2(data["totals"]);
3511
+ const range = asRecord4(data["range"]);
3512
+ const totals = asRecord4(data["totals"]);
2761
3513
  const timeSeries = asRecords2(data["time_series"]).map((row) => ({
2762
- bucket: asString9(row["bucket"]),
2763
- jobs: asNumber6(row["jobs"]),
2764
- items: asNumber6(row["items"]),
2765
- found: asNumber6(row["found"])
3514
+ bucket: asString11(row["bucket"]),
3515
+ jobs: asNumber7(row["jobs"]),
3516
+ items: asNumber7(row["items"]),
3517
+ found: asNumber7(row["found"])
2766
3518
  }));
2767
3519
  const bySource = asRecords2(data["by_source"]).map((row) => ({
2768
- source: asString9(row["source"]),
2769
- jobs: asNumber6(row["jobs"]),
2770
- found: asNumber6(row["found"])
3520
+ source: asString11(row["source"]),
3521
+ jobs: asNumber7(row["jobs"]),
3522
+ found: asNumber7(row["found"])
2771
3523
  }));
2772
3524
  const byOutcome = asRecords2(data["by_outcome"]).map((row) => ({
2773
- outcome: asString9(row["outcome"]),
2774
- count: asNumber6(row["count"])
3525
+ outcome: asString11(row["outcome"]),
3526
+ count: asNumber7(row["count"])
2775
3527
  }));
2776
3528
  const confidenceBuckets = asRecords2(data["confidence_buckets"]).map((row) => ({
2777
- bucket: asString9(row["bucket"]),
2778
- count: asNumber6(row["count"])
3529
+ bucket: asString11(row["bucket"]),
3530
+ count: asNumber7(row["count"])
2779
3531
  }));
2780
3532
  return new _SmartEnrichmentStatistics(
2781
3533
  {
2782
- dateFrom: asString9(range["date_from"]),
2783
- dateTo: asString9(range["date_to"]),
2784
- interval: asString9(range["interval"])
3534
+ dateFrom: asString11(range["date_from"]),
3535
+ dateTo: asString11(range["date_to"]),
3536
+ interval: asString11(range["interval"])
2785
3537
  },
2786
3538
  {
2787
- jobs: asNumber6(totals["jobs"]),
2788
- items: asNumber6(totals["items"]),
2789
- found: asNumber6(totals["found"]),
2790
- foundRate: asNumber6(totals["found_rate"]),
2791
- avgConfidence: asNumber6(totals["avg_confidence"])
3539
+ jobs: asNumber7(totals["jobs"]),
3540
+ items: asNumber7(totals["items"]),
3541
+ found: asNumber7(totals["found"]),
3542
+ foundRate: asNumber7(totals["found_rate"]),
3543
+ avgConfidence: asNumber7(totals["avg_confidence"])
2792
3544
  },
2793
3545
  timeSeries,
2794
3546
  bySource,
@@ -2859,6 +3611,41 @@ var SmartEnrichmentEndpoint = class {
2859
3611
  const data = await this.parseJsonResponse(response);
2860
3612
  return SmartEnrichmentJob.fromArray(data);
2861
3613
  }
3614
+ /**
3615
+ * Search again for rows of a finished lookup that have no usable answer (`not_found`, or a
3616
+ * number registered to another company). Without `rows` every row that qualifies is rechecked.
3617
+ *
3618
+ * Every recheck counts as a check like a new lookup (Deep Verify ×2), whether a VAT number is
3619
+ * found or not. A row can be rechecked up to 3 times, with 7 days between two rechecks;
3620
+ * `no_vat_exists` and found rows are never rechecked. Pass `dryRun` to see which rows would run
3621
+ * and what they cost without starting anything. Improved rows arrive via the
3622
+ * `enrichment.updated` webhook; `get(jobId).recheck` shows the progress.
3623
+ *
3624
+ * Throws a ValidationException when nothing can be rechecked, the lookup is still running, or
3625
+ * rechecks are not available (sandbox, flat-fee import), and an HttpException (429) when the
3626
+ * start credit or monthly hard cap does not cover it.
3627
+ */
3628
+ async recheck(jobId, options = {}) {
3629
+ this.validateJobId(jobId);
3630
+ const body = {};
3631
+ if (options.rows !== void 0) {
3632
+ if (options.rows.length === 0) {
3633
+ throw new TaxoraException("rows must not be empty; omit it to recheck every row that qualifies.");
3634
+ }
3635
+ if (options.rows.some((index) => !Number.isInteger(index) || index < 0)) {
3636
+ throw new TaxoraException("rows must contain 0-based row indexes (integers >= 0).");
3637
+ }
3638
+ body["rows"] = [...new Set(options.rows)];
3639
+ }
3640
+ if (options.dryRun) body["dryRun"] = true;
3641
+ const response = await this.sendRequest(
3642
+ "POST",
3643
+ `${this.baseUrl}/smart-enrichment/${encodeURIComponent(jobId)}/recheck`,
3644
+ body
3645
+ );
3646
+ const data = await this.parseJsonResponse(response, [200, 202]);
3647
+ return SmartEnrichmentRecheck.fromArray(data);
3648
+ }
2862
3649
  /**
2863
3650
  * Poll get(jobId) until the job is no longer processing (completed, failed or resolved).
2864
3651
  * Throws a TaxoraException when the job does not finish within `timeoutMs`.
@@ -4033,7 +4820,7 @@ var AuthRetryHttpClient = class {
4033
4820
  };
4034
4821
 
4035
4822
  // src/version.ts
4036
- var SDK_VERSION = "1.7.1";
4823
+ var SDK_VERSION = "1.9.0";
4037
4824
 
4038
4825
  // src/http/SdkVersionHttpClient.ts
4039
4826
  var SDK_VERSION_HEADER = "X-Taxora-SDK-Version";
@@ -4060,6 +4847,7 @@ var TaxoraClient = class {
4060
4847
  company;
4061
4848
  smartEnrichment;
4062
4849
  eReporting;
4850
+ billing;
4063
4851
  baseUrl;
4064
4852
  constructor(options) {
4065
4853
  const environment = options.environment ?? Environment.SANDBOX;
@@ -4080,6 +4868,7 @@ var TaxoraClient = class {
4080
4868
  retryPolicy
4081
4869
  );
4082
4870
  this.eReporting = new EReportingEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient, retryPolicy);
4871
+ this.billing = new BillingEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient, retryPolicy);
4083
4872
  }
4084
4873
  };
4085
4874
 
@@ -4219,18 +5008,25 @@ function toBytes(rawBody) {
4219
5008
  "invalid_body"
4220
5009
  );
4221
5010
  }
5011
+
5012
+ // src/webhooks/WebhookEvent.ts
5013
+ function isTransactionBuyerRejected(object) {
5014
+ return object.buyer_rejected === true;
5015
+ }
4222
5016
  // Annotate the CommonJS export names for ESM import in node:
4223
5017
  0 && (module.exports = {
4224
5018
  ApiVersion,
4225
5019
  AuthEndpoint,
4226
5020
  AuthRetryHttpClient,
4227
5021
  AuthenticationException,
5022
+ BillingEndpoint,
4228
5023
  CompanyAddress,
4229
5024
  CompanyEndpoint,
4230
5025
  ComplianceDocumentType,
4231
5026
  ComplianceEnrollment,
4232
5027
  ComplianceEnrollmentPage,
4233
5028
  ComplianceEnrollmentStatus,
5029
+ ComplianceOfferings,
4234
5030
  ComplianceService,
4235
5031
  ComplianceTaxReport,
4236
5032
  ComplianceTaxReportPage,
@@ -4264,6 +5060,8 @@ function toBytes(rawBody) {
4264
5060
  SmartEnrichmentHistoryRow,
4265
5061
  SmartEnrichmentJob,
4266
5062
  SmartEnrichmentMode,
5063
+ SmartEnrichmentRecheck,
5064
+ SmartEnrichmentRecheckState,
4267
5065
  SmartEnrichmentRejectionReason,
4268
5066
  SmartEnrichmentResource,
4269
5067
  SmartEnrichmentStatistics,
@@ -4272,6 +5070,8 @@ function toBytes(rawBody) {
4272
5070
  TaxoraClientFactory,
4273
5071
  TaxoraException,
4274
5072
  Token,
5073
+ UsageSummary,
5074
+ UsageSummaryPage,
4275
5075
  ValidationException,
4276
5076
  VatCertificateExport,
4277
5077
  VatCollection,
@@ -4300,6 +5100,7 @@ function toBytes(rawBody) {
4300
5100
  generateWebhookSignatureHeader,
4301
5101
  getBaseUrl,
4302
5102
  getFailedVatStates,
5103
+ isTransactionBuyerRejected,
4303
5104
  parseLocalTaxNumbersCsv,
4304
5105
  parseWebhookSignatureHeader,
4305
5106
  toComplianceDocumentType,