@taxora/sdk 1.0.7 → 1.2.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.d.cts CHANGED
@@ -22,6 +22,75 @@ interface HttpClientInterface {
22
22
  request(method: string, url: string, options?: RequestInit): Promise<Response>;
23
23
  }
24
24
 
25
+ /**
26
+ * How the SDK retries transient failures.
27
+ *
28
+ * Only gateway-level failures are retried by default (502/503/504): those come
29
+ * from the infrastructure in front of the API, not from the API itself, and a
30
+ * second attempt a moment later usually succeeds. Everything else — 4xx, and any
31
+ * answer the API produced itself — is surfaced immediately.
32
+ *
33
+ * On top of that, a 429 is retried when the API answers with a `Retry-After`
34
+ * telling us how long to wait, and connection-level failures (reset connection,
35
+ * client-side timeout, DNS hiccup) are retried as well — those never reached the
36
+ * API's answer either.
37
+ *
38
+ * Retries are opt-in per operation and are only applied to read-only calls
39
+ * (lookups, downloads, polling). Calls that change state or cost quota — booking
40
+ * a transaction, starting an enrichment job, triggering a certificate export —
41
+ * are never retried automatically, because a gateway timeout does not tell us
42
+ * whether the API already processed the request.
43
+ */
44
+ interface RetryPolicyOptions {
45
+ /** Total attempts including the first one (1 disables retrying). */
46
+ maxAttempts?: number;
47
+ initialDelayMs?: number;
48
+ backoffMultiplier?: number;
49
+ maxDelayMs?: number;
50
+ retryableStatusCodes?: number[];
51
+ /** Honour a `Retry-After` header instead of the backoff, and retry a 429 that carries one. */
52
+ respectRetryAfter?: boolean;
53
+ /** Longest wait accepted from `Retry-After`; a longer one means we give up instead of blocking. */
54
+ maxRetryAfterMs?: number;
55
+ /** Retry connection-level failures (reset connection, client-side timeout, DNS hiccup). */
56
+ retryOnNetworkErrors?: boolean;
57
+ /** Receives the delay in milliseconds; defaults to setTimeout. */
58
+ sleeper?: (delayMs: number) => Promise<void> | void;
59
+ }
60
+ declare class RetryPolicy {
61
+ readonly maxAttempts: number;
62
+ readonly initialDelayMs: number;
63
+ readonly backoffMultiplier: number;
64
+ readonly maxDelayMs: number;
65
+ readonly retryableStatusCodes: number[];
66
+ readonly respectRetryAfter: boolean;
67
+ readonly maxRetryAfterMs: number;
68
+ readonly retryOnNetworkErrors: boolean;
69
+ private readonly sleeper;
70
+ constructor(options?: RetryPolicyOptions);
71
+ /** No retrying at all — every failure is surfaced on the first attempt. */
72
+ static disabled(): RetryPolicy;
73
+ /** Retry immediately, without waiting (mainly useful in tests). */
74
+ static withoutDelay(maxAttempts?: number): RetryPolicy;
75
+ isRetryable(statusCode: number, retryAfterHeader?: string | null): boolean;
76
+ /** @param attempt Number of attempts made so far (1 = the first one just failed). */
77
+ shouldRetry(statusCode: number, attempt: number, retryAfterHeader?: string | null): boolean;
78
+ /**
79
+ * A connection-level failure: the request never got an answer, so repeating it
80
+ * is as safe as repeating a gateway timeout.
81
+ */
82
+ isRetryableError(error: unknown): boolean;
83
+ shouldRetryError(error: unknown, attempt: number): boolean;
84
+ /**
85
+ * The wait the API asked for, in milliseconds — seconds or HTTP-date form — or
86
+ * null when there is none, it cannot be parsed, or the header is ignored.
87
+ */
88
+ retryAfterMs(header: string | null | undefined, now?: Date): number | null;
89
+ /** The wait before the next attempt: what the API asked for, else exponential backoff. */
90
+ delayMsForAttempt(attempt: number, retryAfterHeader?: string | null): number;
91
+ sleepBeforeRetry(attempt: number, retryAfterHeader?: string | null): Promise<void>;
92
+ }
93
+
25
94
  interface TokenStorageInterface {
26
95
  get(): Token | null;
27
96
  set(token: Token): void;
@@ -33,7 +102,8 @@ declare class AuthEndpoint {
33
102
  private readonly apiKey;
34
103
  private readonly tokenStorage;
35
104
  private readonly httpClient;
36
- constructor(baseUrl: string, apiKey: string, tokenStorage: TokenStorageInterface, httpClient: HttpClientInterface);
105
+ private readonly retryPolicy;
106
+ constructor(baseUrl: string, apiKey: string, tokenStorage: TokenStorageInterface, httpClient: HttpClientInterface, retryPolicy?: RetryPolicy);
37
107
  login(identifier: string, password: string, device?: string, loginIdentifier?: LoginIdentifier): Promise<Token>;
38
108
  loginWithClientId(clientId: string, password: string, device?: string): Promise<Token>;
39
109
  refresh(): Promise<Token>;
@@ -69,10 +139,988 @@ declare class CompanyEndpoint {
69
139
  private readonly apiKey;
70
140
  private readonly tokenStorage;
71
141
  private readonly httpClient;
72
- constructor(baseUrl: string, apiKey: string, tokenStorage: TokenStorageInterface, httpClient: HttpClientInterface);
142
+ private readonly retryPolicy;
143
+ constructor(baseUrl: string, apiKey: string, tokenStorage: TokenStorageInterface, httpClient: HttpClientInterface, retryPolicy?: RetryPolicy);
73
144
  get(): Promise<CompanyResource>;
74
145
  }
75
146
 
147
+ declare const ComplianceEnrollmentStatus: {
148
+ readonly PENDING_DATA: "pending_data";
149
+ readonly ACCOUNT_CREATED: "account_created";
150
+ readonly REGIME_ACTIVATED: "regime_activated";
151
+ readonly READY: "ready";
152
+ readonly SUSPENDED: "suspended";
153
+ readonly ERROR_ACCOUNT: "error_account";
154
+ readonly ERROR_ACTIVATION: "error_activation";
155
+ readonly UNKNOWN: "unknown";
156
+ };
157
+ type ComplianceEnrollmentStatus = (typeof ComplianceEnrollmentStatus)[keyof typeof ComplianceEnrollmentStatus];
158
+ /** Tolerant coercion: unrecognized values become `unknown` instead of throwing. */
159
+ declare function toComplianceEnrollmentStatus(value: unknown): ComplianceEnrollmentStatus;
160
+ declare function describeComplianceEnrollmentStatus(status: ComplianceEnrollmentStatus): string;
161
+
162
+ /**
163
+ * A compliance enrollment — the merchant's provisioned e-reporting account for
164
+ * one reporting country/regime (GET/POST /compliance/enrollments).
165
+ */
166
+ declare class ComplianceEnrollment {
167
+ readonly id: number;
168
+ readonly companyId: number;
169
+ readonly country: string;
170
+ readonly regime: string;
171
+ readonly provider: string;
172
+ readonly status: ComplianceEnrollmentStatus;
173
+ readonly statusLabel: string;
174
+ readonly statusError: string | null;
175
+ readonly providerAccountId: string | null;
176
+ readonly taxId: string | null;
177
+ readonly companyRegisterId: string | null;
178
+ readonly companyRegisterScheme: string | null;
179
+ readonly regimeConfig: Record<string, unknown> | null;
180
+ /** First date transactions are reported for (YYYY-MM-DD). */
181
+ readonly reportingStartDate: string | null;
182
+ readonly notificationEmail: string | null;
183
+ readonly autoSend: boolean;
184
+ readonly createdAt: string | null;
185
+ readonly updatedAt: string | null;
186
+ constructor(id: number, companyId: number, country: string, regime: string, provider: string, status: ComplianceEnrollmentStatus, statusLabel: string, statusError: string | null, providerAccountId: string | null, taxId: string | null, companyRegisterId: string | null, companyRegisterScheme: string | null, regimeConfig: Record<string, unknown> | null,
187
+ /** First date transactions are reported for (YYYY-MM-DD). */
188
+ reportingStartDate: string | null, notificationEmail: string | null, autoSend: boolean, createdAt: string | null, updatedAt: string | null);
189
+ static fromArray(data: Record<string, unknown>): ComplianceEnrollment;
190
+ }
191
+
192
+ /**
193
+ * A paginated page of compliance enrollments (GET /compliance/enrollments).
194
+ */
195
+ declare class ComplianceEnrollmentPage implements Iterable<ComplianceEnrollment> {
196
+ readonly rows: ComplianceEnrollment[];
197
+ readonly currentPage: number;
198
+ readonly perPage: number;
199
+ readonly total: number;
200
+ readonly lastPage: number;
201
+ constructor(rows: ComplianceEnrollment[], currentPage: number, perPage: number, total: number, lastPage: number);
202
+ static fromResponse(payload: unknown): ComplianceEnrollmentPage;
203
+ [Symbol.iterator](): Iterator<ComplianceEnrollment>;
204
+ get length(): number;
205
+ }
206
+
207
+ declare const ComplianceTaxReportState: {
208
+ readonly NEW: "new";
209
+ readonly SENT: "sent";
210
+ readonly ACKNOWLEDGED: "acknowledged";
211
+ readonly REGISTERED: "registered";
212
+ readonly REFUSED: "refused";
213
+ readonly ERROR: "error";
214
+ readonly UNKNOWN: "unknown";
215
+ };
216
+ type ComplianceTaxReportState = (typeof ComplianceTaxReportState)[keyof typeof ComplianceTaxReportState];
217
+ /** Tolerant coercion: unrecognized values become `unknown` instead of throwing. */
218
+ declare function toComplianceTaxReportState(value: unknown): ComplianceTaxReportState;
219
+ declare function describeComplianceTaxReportState(state: ComplianceTaxReportState): string;
220
+
221
+ /**
222
+ * A DGFiP tax report tracking one transaction through the aggregated daily
223
+ * ledger lifecycle (GET /compliance/tax-reports).
224
+ */
225
+ declare class ComplianceTaxReport {
226
+ readonly id: number;
227
+ readonly companyId: number;
228
+ readonly complianceTransactionId: number | null;
229
+ readonly ledgerId: number | null;
230
+ readonly country: string;
231
+ readonly regime: string;
232
+ readonly state: ComplianceTaxReportState;
233
+ readonly stateLabel: string;
234
+ /** True once the report reached a final state (registered, refused or error). */
235
+ readonly isTerminal: boolean;
236
+ readonly providerTaxReportId: string | null;
237
+ readonly providerLedgerId: string | null;
238
+ readonly baseAmount: string;
239
+ readonly taxAmount: string;
240
+ readonly totalAmount: string;
241
+ readonly refusalReason: string | null;
242
+ readonly registeredAt: string | null;
243
+ readonly refusedAt: string | null;
244
+ readonly createdAt: string | null;
245
+ readonly updatedAt: string | null;
246
+ constructor(id: number, companyId: number, complianceTransactionId: number | null, ledgerId: number | null, country: string, regime: string, state: ComplianceTaxReportState, stateLabel: string,
247
+ /** True once the report reached a final state (registered, refused or error). */
248
+ isTerminal: boolean, providerTaxReportId: string | null, providerLedgerId: string | null, baseAmount: string, taxAmount: string, totalAmount: string, refusalReason: string | null, registeredAt: string | null, refusedAt: string | null, createdAt: string | null, updatedAt: string | null);
249
+ static fromArray(data: Record<string, unknown>): ComplianceTaxReport;
250
+ }
251
+
252
+ /**
253
+ * A paginated page of compliance tax reports (GET /compliance/tax-reports).
254
+ */
255
+ declare class ComplianceTaxReportPage implements Iterable<ComplianceTaxReport> {
256
+ readonly rows: ComplianceTaxReport[];
257
+ readonly currentPage: number;
258
+ readonly perPage: number;
259
+ readonly total: number;
260
+ readonly lastPage: number;
261
+ constructor(rows: ComplianceTaxReport[], currentPage: number, perPage: number, total: number, lastPage: number);
262
+ static fromResponse(payload: unknown): ComplianceTaxReportPage;
263
+ [Symbol.iterator](): Iterator<ComplianceTaxReport>;
264
+ get length(): number;
265
+ }
266
+
267
+ declare const ComplianceTransactionState: {
268
+ readonly PENDING: "pending";
269
+ readonly SENDING: "sending";
270
+ readonly SUBMITTED: "submitted";
271
+ readonly ERROR: "error";
272
+ readonly UNKNOWN: "unknown";
273
+ };
274
+ type ComplianceTransactionState = (typeof ComplianceTransactionState)[keyof typeof ComplianceTransactionState];
275
+ /** Tolerant coercion: unrecognized values become `unknown` instead of throwing. */
276
+ declare function toComplianceTransactionState(value: unknown): ComplianceTransactionState;
277
+ declare function describeComplianceTransactionState(state: ComplianceTransactionState): string;
278
+
279
+ declare const ComplianceTransactionType: {
280
+ readonly B2C_OUTBOUND: "b2c_outbound";
281
+ readonly B2B_DOMESTIC_OUTBOUND: "b2b_domestic_outbound";
282
+ readonly B2B_DOMESTIC_INBOUND: "b2b_domestic_inbound";
283
+ readonly CROSSBORDER_OUTBOUND: "crossborder_outbound";
284
+ readonly CROSSBORDER_INBOUND: "crossborder_inbound";
285
+ readonly UNKNOWN: "unknown";
286
+ };
287
+ type ComplianceTransactionType = (typeof ComplianceTransactionType)[keyof typeof ComplianceTransactionType];
288
+ /** Tolerant coercion: unrecognized values become `unknown` instead of throwing. */
289
+ declare function toComplianceTransactionType(value: unknown): ComplianceTransactionType;
290
+ declare function describeComplianceTransactionType(type: ComplianceTransactionType): string;
291
+
292
+ /**
293
+ * A recorded e-reporting transaction (GET/POST /compliance/transactions).
294
+ */
295
+ declare class ComplianceTransaction {
296
+ readonly id: number;
297
+ readonly companyId: number;
298
+ readonly complianceEnrollmentId: number;
299
+ readonly country: string;
300
+ readonly regime: string;
301
+ readonly transactionType: ComplianceTransactionType;
302
+ readonly transactionTypeLabel: string;
303
+ readonly state: ComplianceTransactionState;
304
+ readonly stateLabel: string;
305
+ readonly invoiceNumber: string;
306
+ /** Invoice date (YYYY-MM-DD). */
307
+ readonly invoiceDate: string | null;
308
+ readonly dueDate: string | null;
309
+ readonly currency: string;
310
+ readonly subtotal: string;
311
+ readonly taxAmount: string;
312
+ readonly total: string;
313
+ readonly counterpartyName: string | null;
314
+ readonly counterpartyCountry: string | null;
315
+ readonly counterpartyVatNumber: string | null;
316
+ readonly isPaid: boolean;
317
+ readonly paidAt: string | null;
318
+ readonly providerInvoiceId: string | null;
319
+ readonly submissionError: string | null;
320
+ readonly reportedAt: string | null;
321
+ /** Associated DGFiP tax report; undefined when the API did not include it. */
322
+ readonly taxReport: ComplianceTaxReport | undefined;
323
+ readonly createdAt: string | null;
324
+ readonly updatedAt: string | null;
325
+ constructor(id: number, companyId: number, complianceEnrollmentId: number, country: string, regime: string, transactionType: ComplianceTransactionType, transactionTypeLabel: string, state: ComplianceTransactionState, stateLabel: string, invoiceNumber: string,
326
+ /** Invoice date (YYYY-MM-DD). */
327
+ invoiceDate: string | null, dueDate: string | null, currency: string, subtotal: string, taxAmount: string, total: string, counterpartyName: string | null, counterpartyCountry: string | null, counterpartyVatNumber: string | null, isPaid: boolean, paidAt: string | null, providerInvoiceId: string | null, submissionError: string | null, reportedAt: string | null,
328
+ /** Associated DGFiP tax report; undefined when the API did not include it. */
329
+ taxReport: ComplianceTaxReport | undefined, createdAt: string | null, updatedAt: string | null);
330
+ static fromArray(data: Record<string, unknown>): ComplianceTransaction;
331
+ }
332
+
333
+ /**
334
+ * A paginated page of compliance transactions (GET /compliance/transactions).
335
+ */
336
+ declare class ComplianceTransactionPage implements Iterable<ComplianceTransaction> {
337
+ readonly rows: ComplianceTransaction[];
338
+ readonly currentPage: number;
339
+ readonly perPage: number;
340
+ readonly total: number;
341
+ readonly lastPage: number;
342
+ constructor(rows: ComplianceTransaction[], currentPage: number, perPage: number, total: number, lastPage: number);
343
+ static fromResponse(payload: unknown): ComplianceTransactionPage;
344
+ [Symbol.iterator](): Iterator<ComplianceTransaction>;
345
+ get length(): number;
346
+ }
347
+
348
+ /**
349
+ * Result of a CSV transaction import (POST /compliance/transactions/import).
350
+ */
351
+ declare class ImportResult {
352
+ /** Number of transactions created from the file. */
353
+ readonly created: number;
354
+ /** Rows skipped because a matching transaction already exists (idempotent re-upload). */
355
+ readonly skippedDuplicates: number;
356
+ /** Row-level errors, e.g. "Row 3 (INV-1): invalid transaction_type 'x'". */
357
+ readonly errors: string[];
358
+ constructor(
359
+ /** Number of transactions created from the file. */
360
+ created: number,
361
+ /** Rows skipped because a matching transaction already exists (idempotent re-upload). */
362
+ skippedDuplicates: number,
363
+ /** Row-level errors, e.g. "Row 3 (INV-1): invalid transaction_type 'x'". */
364
+ errors: string[]);
365
+ static fromArray(data: Record<string, unknown>): ImportResult;
366
+ }
367
+
368
+ /**
369
+ * DTOs for the e-reporting revenue statistics endpoint
370
+ * (GET /compliance/revenue-statistics).
371
+ *
372
+ * Monetary values are kept as the 4-decimal strings returned by the API (no
373
+ * Number conversion) to preserve precision. All headline figures are expressed
374
+ * in `primaryCurrency`; when `isMultiCurrency` is true, `byCurrency` lists every
375
+ * currency present in the range.
376
+ */
377
+ interface RevenueTotals {
378
+ count: number;
379
+ subtotal: string;
380
+ taxAmount: string;
381
+ total: string;
382
+ }
383
+ interface RevenueTimeBucket extends RevenueTotals {
384
+ /** Period key: "2026-01-15" (day), "2026-03" (ISO year-week) or "2026-01" (month). */
385
+ bucket: string;
386
+ }
387
+ interface RevenueTypeBreakdown {
388
+ type: string;
389
+ typeLabel: string;
390
+ count: number;
391
+ total: string;
392
+ }
393
+ interface RevenueCountryBreakdown {
394
+ /** Counterparty country code; "unknown" groups transactions with no partner country. */
395
+ country: string;
396
+ count: number;
397
+ total: string;
398
+ }
399
+ interface RevenueStateBreakdown {
400
+ state: string;
401
+ stateLabel: string;
402
+ count: number;
403
+ total: string;
404
+ }
405
+ interface RevenueCurrencyBreakdown extends RevenueTotals {
406
+ currency: string;
407
+ }
408
+ declare class RevenueStatistics {
409
+ readonly dateFrom: string | undefined;
410
+ readonly dateTo: string | undefined;
411
+ readonly interval: string | undefined;
412
+ readonly primaryCurrency: string;
413
+ readonly isMultiCurrency: boolean;
414
+ readonly totals: RevenueTotals;
415
+ readonly timeSeries: RevenueTimeBucket[];
416
+ readonly byType: RevenueTypeBreakdown[];
417
+ readonly byCountry: RevenueCountryBreakdown[];
418
+ readonly byState: RevenueStateBreakdown[];
419
+ readonly byCurrency: RevenueCurrencyBreakdown[];
420
+ constructor(dateFrom: string | undefined, dateTo: string | undefined, interval: string | undefined, primaryCurrency: string, isMultiCurrency: boolean, totals: RevenueTotals, timeSeries: RevenueTimeBucket[], byType: RevenueTypeBreakdown[], byCountry: RevenueCountryBreakdown[], byState: RevenueStateBreakdown[], byCurrency: RevenueCurrencyBreakdown[]);
421
+ static fromArray(data: Record<string, unknown>): RevenueStatistics;
422
+ }
423
+
424
+ /**
425
+ * Company data resolved from the French SIRENE registry
426
+ * (GET /compliance/sirene-lookup). Maps 1:1 onto the createEnrollment input.
427
+ */
428
+ declare class SireneLookupResult {
429
+ readonly companyName: string;
430
+ readonly siren: string;
431
+ readonly siret: string | null;
432
+ /** 2-digit NAF division, e.g. "47". */
433
+ readonly nafCode: string | null;
434
+ /** Full NAF/APE code, e.g. "47.11D". */
435
+ readonly nafFull: string | null;
436
+ /** Mapped enterprise size ("micro", "pme", "eti" or "ge"); null when unmappable. */
437
+ readonly enterpriseSize: string | null;
438
+ readonly address: string | null;
439
+ readonly city: string | null;
440
+ readonly postalcode: string | null;
441
+ constructor(companyName: string, siren: string, siret: string | null,
442
+ /** 2-digit NAF division, e.g. "47". */
443
+ nafCode: string | null,
444
+ /** Full NAF/APE code, e.g. "47.11D". */
445
+ nafFull: string | null,
446
+ /** Mapped enterprise size ("micro", "pme", "eti" or "ge"); null when unmappable. */
447
+ enterpriseSize: string | null, address: string | null, city: string | null, postalcode: string | null);
448
+ static fromArray(data: Record<string, unknown>): SireneLookupResult;
449
+ }
450
+
451
+ /**
452
+ * One VAT rate / DGFiP tax category offered for a reporting country.
453
+ */
454
+ interface VatRate {
455
+ /** VAT percentage, e.g. 20 or 5.5. */
456
+ percent: number;
457
+ /** DGFiP tax category code (S/AA/AAA/K/G/AE/E/Z). */
458
+ category: string;
459
+ /** i18n key for the rate label, e.g. "fr_standard". */
460
+ labelKey: string;
461
+ /** Default tax designation prefilled into invoice lines, e.g. "TVA". */
462
+ taxName: string;
463
+ /** True when a VATEX exemption code is mandatory in the line's `comment` (category E). */
464
+ requiresVatex: boolean;
465
+ }
466
+ /**
467
+ * The canonical VAT rates & DGFiP tax categories for a reporting country
468
+ * (GET /compliance/vat-rates).
469
+ */
470
+ declare class VatRates {
471
+ readonly country: string;
472
+ readonly currency: string;
473
+ readonly rates: VatRate[];
474
+ constructor(country: string, currency: string, rates: VatRate[]);
475
+ static fromArray(data: Record<string, unknown>): VatRates;
476
+ }
477
+
478
+ /** Time-series bucket size accepted by the revenue statistics endpoint. */
479
+ type EReportingInterval = 'day' | 'week' | 'month';
480
+ /** Enterprise size categories accepted by the DGFiP enrollment. */
481
+ type ComplianceEnterpriseSize = 'micro' | 'pme' | 'eti' | 'ge';
482
+ /** Type of operations the enrolled company performs. */
483
+ type ComplianceTypeOperation = 'services' | 'goods' | 'mixed';
484
+ /** Transaction types accepted on the request side (the tolerant `unknown` is response-only). */
485
+ type ComplianceTransactionRequestType = Exclude<ComplianceTransactionType, 'unknown'>;
486
+ /** Transaction states accepted as filters (the tolerant `unknown` is response-only). */
487
+ type ComplianceTransactionRequestState = Exclude<ComplianceTransactionState, 'unknown'>;
488
+ /** Tax report states accepted as filters (the tolerant `unknown` is response-only). */
489
+ type ComplianceTaxReportRequestState = Exclude<ComplianceTaxReportState, 'unknown'>;
490
+ interface RevenueStatisticsFilters {
491
+ dateFrom?: Date | string;
492
+ dateTo?: Date | string;
493
+ /** Time-series bucket size. Defaults to "month" server-side. */
494
+ interval?: EReportingInterval;
495
+ transactionType?: ComplianceTransactionRequestType;
496
+ state?: ComplianceTransactionRequestState;
497
+ }
498
+ interface CreateComplianceEnrollmentInput {
499
+ /** Reporting country (2-char ISO 3166-1 alpha-2). Defaults server-side (FR). */
500
+ country?: string;
501
+ /** Compliance regime, e.g. "dgfip_flux10". Defaults server-side. */
502
+ regime?: string;
503
+ /** 14-digit SIRET. Required unless `siren` is set. */
504
+ siret?: string;
505
+ /** 9-digit SIREN. Required unless `siret` is set. */
506
+ siren?: string;
507
+ vatNumber?: string;
508
+ companyName?: string;
509
+ address?: string;
510
+ city?: string;
511
+ postalcode?: string;
512
+ province?: string;
513
+ /** Notification email for the provider account. */
514
+ email: string;
515
+ /** 2-digit NAF division, e.g. "47". */
516
+ nafCode: string;
517
+ enterpriseSize: ComplianceEnterpriseSize;
518
+ typeOperation: ComplianceTypeOperation;
519
+ /** First date transactions are reported for (Date or strict YYYY-MM-DD). */
520
+ reportingStartDate: Date | string;
521
+ /** When false, only the provider account is created — the DGFiP regime is NOT activated. Defaults to true server-side. */
522
+ autoActivate?: boolean;
523
+ }
524
+ interface ComplianceInvoiceTaxInput {
525
+ /** Tax designation, e.g. "TVA". */
526
+ name: string;
527
+ /** VAT percentage, e.g. 20 or 5.5. */
528
+ percent: number;
529
+ /** DGFiP tax category code (S/AA/AAA/K/G/AE/E/Z) — see getVatRates(). */
530
+ category: string;
531
+ /** VATEX exemption code; required when `category` is "E". */
532
+ comment?: string;
533
+ }
534
+ interface ComplianceInvoiceLineInput {
535
+ description: string;
536
+ quantity: number;
537
+ price: number;
538
+ /** UN/ECE unit code, e.g. 9 (each). */
539
+ unit?: number;
540
+ /** At least one tax per line. */
541
+ taxes: ComplianceInvoiceTaxInput[];
542
+ }
543
+ interface CreateComplianceTransactionInput {
544
+ complianceEnrollmentId: number;
545
+ transactionType: ComplianceTransactionRequestType;
546
+ invoiceNumber: string;
547
+ /** Invoice date (Date or strict YYYY-MM-DD). */
548
+ invoiceDate: Date | string;
549
+ subtotal: number;
550
+ total: number;
551
+ /** At least one invoice line, each with at least one tax. */
552
+ invoiceLines: ComplianceInvoiceLineInput[];
553
+ dueDate?: Date | string;
554
+ /** 3-char ISO 4217 code. Defaults to EUR server-side. */
555
+ currency?: string;
556
+ taxAmount?: number;
557
+ counterpartyName?: string;
558
+ /** 2-char ISO 3166-1 alpha-2 code. */
559
+ counterpartyCountry?: string;
560
+ counterpartyVatNumber?: string;
561
+ providerContactId?: string;
562
+ /** Payment means code; required for cross-border outbound. */
563
+ paymentMethod?: number;
564
+ remittanceInformation?: string;
565
+ paymentMethodText?: string;
566
+ paymentTerms?: string;
567
+ /** When false, the transaction is only recorded — submission is deferred. Defaults to true server-side. */
568
+ submitNow?: boolean;
569
+ }
570
+ interface UpdateComplianceTransactionInput {
571
+ transactionType?: ComplianceTransactionRequestType;
572
+ invoiceNumber?: string;
573
+ invoiceDate?: Date | string;
574
+ dueDate?: Date | string;
575
+ /** 3-char ISO 4217 code. */
576
+ currency?: string;
577
+ subtotal?: number;
578
+ taxAmount?: number;
579
+ total?: number;
580
+ counterpartyName?: string;
581
+ /** 2-char ISO 3166-1 alpha-2 code. */
582
+ counterpartyCountry?: string;
583
+ counterpartyVatNumber?: string;
584
+ providerContactId?: string;
585
+ /** When set: at least one invoice line, each with at least one tax. */
586
+ invoiceLines?: ComplianceInvoiceLineInput[];
587
+ paymentMethod?: number;
588
+ remittanceInformation?: string;
589
+ paymentMethodText?: string;
590
+ paymentTerms?: string;
591
+ }
592
+ interface ComplianceTransactionFilters {
593
+ /** Inclusive lower bound on the invoice date (Date or strict YYYY-MM-DD). */
594
+ dateFrom?: Date | string;
595
+ /** Inclusive upper bound on the invoice date (Date or strict YYYY-MM-DD). */
596
+ dateTo?: Date | string;
597
+ state?: ComplianceTransactionRequestState;
598
+ transactionType?: ComplianceTransactionRequestType;
599
+ page?: number;
600
+ /** Page size (1-100, default 25 server-side). */
601
+ perPage?: number;
602
+ }
603
+ interface EReportingAccessRequestInput {
604
+ name?: string;
605
+ email?: string;
606
+ company?: string;
607
+ phone?: string;
608
+ message?: string;
609
+ /** Locale for the confirmation mail, e.g. "de" or "en". */
610
+ language?: string;
611
+ }
612
+ /**
613
+ * E-Reporting / Compliance (DGFiP Flux 10) endpoints.
614
+ *
615
+ * Typical flow: sireneLookup() to prefill company data, createEnrollment() to
616
+ * provision the provider account, then createTransaction() / importTransactions()
617
+ * to record invoices and listTaxReports() to track their DGFiP lifecycle.
618
+ *
619
+ * All routes except requestEReportingAccess() require an active E-Reporting
620
+ * subscription / feature grant on the account.
621
+ */
622
+ declare class EReportingEndpoint {
623
+ private readonly baseUrl;
624
+ private readonly apiKey;
625
+ private readonly tokenStorage;
626
+ private readonly httpClient;
627
+ private readonly retryPolicy;
628
+ constructor(baseUrl: string, apiKey: string, tokenStorage: TokenStorageInterface, httpClient: HttpClientInterface, retryPolicy?: RetryPolicy);
629
+ /**
630
+ * Create a compliance enrollment and provision the provider account. By
631
+ * default the DGFiP regime is activated right away; pass `autoActivate: false`
632
+ * to only create the account.
633
+ *
634
+ * On provider failure the API responds 502 (mapped to an HttpException) and
635
+ * the enrollment is persisted in `error_account`/`error_activation` state so
636
+ * provisioning can be retried.
637
+ */
638
+ createEnrollment(input: CreateComplianceEnrollmentInput): Promise<ComplianceEnrollment>;
639
+ /** Paginated list of the company's enrollments (newest first). `perPage` is capped at 100 server-side. */
640
+ listEnrollments(page?: number, perPage?: number): Promise<ComplianceEnrollmentPage>;
641
+ /** Get a single enrollment by id. */
642
+ getEnrollment(id: number): Promise<ComplianceEnrollment>;
643
+ /**
644
+ * Look up company data by SIRET, SIREN or French VAT number via the French
645
+ * SIRENE registry — ideal for prefilling createEnrollment().
646
+ *
647
+ * Rate-limited to 3 requests/minute per user (protects the external French
648
+ * government API); exceeding it yields a 429 (mapped to an HttpException).
649
+ */
650
+ sireneLookup(q: string): Promise<SireneLookupResult>;
651
+ /**
652
+ * Record and (by default) submit a Flux 10 transaction. Pass `submitNow: false`
653
+ * to only record it — submission can be triggered later via submitTransaction().
654
+ *
655
+ * Immediate per-invoice submission requires the e-invoicing feature on the
656
+ * account; in pure e-reporting mode the transaction is only recorded and
657
+ * reported via the aggregated daily ledgers.
658
+ *
659
+ * Creation is idempotent on the invoice's natural key (enrollment, type,
660
+ * invoice number, invoice date, counterparty VAT): a re-sent create returns
661
+ * the existing transaction with HTTP 200 instead of creating a duplicate.
662
+ *
663
+ * On provider failure the API responds 502 (mapped to an HttpException).
664
+ */
665
+ createTransaction(input: CreateComplianceTransactionInput): Promise<ComplianceTransaction>;
666
+ /** Paginated list of the company's transactions (newest invoice date first), filterable by date / state / type. */
667
+ listTransactions(filters?: ComplianceTransactionFilters): Promise<ComplianceTransactionPage>;
668
+ /** Get a single transaction by id (includes its tax report when one exists). */
669
+ getTransaction(id: number): Promise<ComplianceTransaction>;
670
+ /** Update a still-pending transaction. Only the provided fields are sent; already-submitted transactions are rejected with 422. */
671
+ updateTransaction(id: number, input: UpdateComplianceTransactionInput): Promise<ComplianceTransaction>;
672
+ /** Delete a still-pending transaction. Already-submitted transactions are rejected with 422. */
673
+ deleteTransaction(id: number): Promise<void>;
674
+ /**
675
+ * Submit (or retry) an existing `pending`/`error` transaction to the provider.
676
+ * Replays the invoice lines stored at creation, so they don't have to be re-sent.
677
+ *
678
+ * Requires the e-invoicing feature on the account — pure e-reporting customers
679
+ * get a 422 (transactions are reported via the aggregated daily ledgers instead).
680
+ *
681
+ * On provider failure the API responds 502 (mapped to an HttpException);
682
+ * already-submitted transactions are rejected with 422.
683
+ */
684
+ submitTransaction(id: number): Promise<ComplianceTransaction>;
685
+ /**
686
+ * Bulk-import transactions from a semicolon-separated CSV (one row per invoice
687
+ * line; rows sharing an invoice_number are grouped into one transaction).
688
+ * Required columns: invoice_number, invoice_date, transaction_type, subtotal,
689
+ * total, line_description, line_quantity, line_price, tax_name, tax_percent,
690
+ * tax_category.
691
+ *
692
+ * The import is idempotent: re-uploading the same file skips rows whose
693
+ * invoice already exists (reported via `skippedDuplicates`).
694
+ */
695
+ importTransactions(enrollmentId: number, csvContent: string, filename?: string): Promise<ImportResult>;
696
+ /**
697
+ * Aggregated turnover statistics for the authenticated company's e-reporting
698
+ * transactions. All arguments are optional — the API defaults to the last 12
699
+ * months and a monthly interval.
700
+ */
701
+ getRevenueStatistics(filters?: RevenueStatisticsFilters): Promise<RevenueStatistics>;
702
+ /**
703
+ * The canonical VAT rates & DGFiP tax categories for a reporting country
704
+ * (the seller's reporting-country rates, not the counterparty's). Falls back
705
+ * to the configured default country (FR) when none/unknown is given.
706
+ */
707
+ getVatRates(country?: string): Promise<VatRates>;
708
+ /** Paginated list of the company's tax reports (newest first), optionally filtered by state. */
709
+ listTaxReports(page?: number, perPage?: number, state?: ComplianceTaxReportRequestState): Promise<ComplianceTaxReportPage>;
710
+ /** Get a single tax report by id. */
711
+ getTaxReport(id: number): Promise<ComplianceTaxReport>;
712
+ /**
713
+ * Request activation of the E-Reporting feature for the account. This route
714
+ * is deliberately NOT gated by compliance access — it exists precisely for
715
+ * accounts that do not have the feature yet. The authenticated user's
716
+ * name/email take precedence over the form values server-side.
717
+ *
718
+ * Note: unlike the other compliance routes, validation failures here are
719
+ * returned as HTTP 400 (surfaced as HttpException), not 422.
720
+ */
721
+ requestEReportingAccess(input?: EReportingAccessRequestInput): Promise<void>;
722
+ private validateEnrollmentInput;
723
+ private validateId;
724
+ private validateTransactionType;
725
+ private validateInvoiceNumber;
726
+ private validateInvoiceLines;
727
+ private validateOptionalCodes;
728
+ private buildInvoiceLines;
729
+ /** Applies the optional scalar fields shared by create and update. */
730
+ private applyOptionalTransactionFields;
731
+ private buildHeaders;
732
+ private sendRequest;
733
+ /** Multipart upload: Content-Type is left to fetch so the boundary is set correctly. */
734
+ private sendMultipartRequest;
735
+ /** Accepts any 2xx response (e.g. 201 on create, 200 on idempotent replay). */
736
+ private parseJsonResponse;
737
+ /** For the 204 delete: keeps the shared 422/HTTP error mapping but never parses a body. */
738
+ private assertNoContentResponse;
739
+ /**
740
+ * The backend emits two 422 shapes: Laravel FormRequest failures as
741
+ * `{message, errors: {field: [...]}}` and state-guard errors via returnError()
742
+ * as `{error: "reason"}`. Preserve the reason in both cases.
743
+ */
744
+ private buildValidationException;
745
+ /**
746
+ * Date objects are serialized from their LOCAL date parts — construct them as
747
+ * `new Date('2026-09-01T00:00:00')` (local midnight); a bare `new Date('2026-09-01')`
748
+ * is UTC midnight and shifts a day back in UTC-negative timezones.
749
+ */
750
+ private formatDate;
751
+ }
752
+
753
+ /**
754
+ * How hard a Smart Enrichment lookup is allowed to search.
755
+ *
756
+ * `default` searches with one AI provider and consults a second one only when the first finds
757
+ * nothing — one paid search per lookup in the common case.
758
+ *
759
+ * `complex` has two independent AI providers search from the start, and every VAT number either of
760
+ * them proposes is put through the tax authority's checks until one confirms. Noticeably better on
761
+ * hard lookups — companies whose VAT only appears in a website Impressum — and it costs more per
762
+ * lookup, so it is opt-in per request rather than the default.
763
+ */
764
+ declare const SmartEnrichmentMode: {
765
+ readonly DEFAULT: "default";
766
+ readonly COMPLEX: "complex";
767
+ };
768
+ type SmartEnrichmentMode = (typeof SmartEnrichmentMode)[keyof typeof SmartEnrichmentMode];
769
+ /**
770
+ * Coercion for values coming back from the API. Returns undefined for anything unrecognized —
771
+ * unlike the status enum there is no `unknown` member to fall back to, and inventing a mode would
772
+ * misreport how a lookup actually ran.
773
+ */
774
+ declare function toSmartEnrichmentMode(value: unknown): SmartEnrichmentMode | undefined;
775
+ declare function describeSmartEnrichmentMode(mode: SmartEnrichmentMode): string;
776
+
777
+ declare const SmartEnrichmentStatus: {
778
+ readonly FOUND: "found";
779
+ readonly NO_VAT_EXISTS: "no_vat_exists";
780
+ readonly NOT_FOUND: "not_found";
781
+ readonly PROCESSING: "processing";
782
+ readonly QUEUED: "queued";
783
+ readonly COMPLETED: "completed";
784
+ readonly FAILED: "failed";
785
+ readonly UNKNOWN: "unknown";
786
+ };
787
+ type SmartEnrichmentStatus = (typeof SmartEnrichmentStatus)[keyof typeof SmartEnrichmentStatus];
788
+ /** Tolerant coercion: unrecognized values become `unknown` instead of throwing. */
789
+ declare function toSmartEnrichmentStatus(value: unknown): SmartEnrichmentStatus;
790
+ declare function describeSmartEnrichmentStatus(status: SmartEnrichmentStatus): string;
791
+
792
+ /** What one AI provider independently concluded, when more than one searched. */
793
+ interface SmartEnrichmentProviderVerdict {
794
+ provider: string;
795
+ model: string | null;
796
+ status: string;
797
+ vatNumber: string | null;
798
+ confidence: number | null;
799
+ /** False when the model answered from memory instead of an actual web search. */
800
+ grounded: boolean;
801
+ sourceUrl: string | null;
802
+ }
803
+ /**
804
+ * What the API made of the address you submitted. The actionable part is `warnings`:
805
+ * `postal_code_city_mismatch` / `postal_code_unassigned` / `postal_code_format_invalid` mean the
806
+ * postal code in your source record is wrong, and `derivedPlace` is where it actually points —
807
+ * worth writing back into your own data.
808
+ */
809
+ interface SmartEnrichmentAddressQuality {
810
+ providedPostalCode: string | null;
811
+ providedCity: string | null;
812
+ postalCodeFormatValid: boolean | null;
813
+ postalCodeAssigned: boolean | null;
814
+ /** False when the postal code was excluded from the search because it could not be trusted. */
815
+ postalCodeTrusted: boolean;
816
+ derivedPlace: string | null;
817
+ cityMatchesPostalCode: boolean | null;
818
+ warnings: string[];
819
+ }
820
+ /**
821
+ * Result of resolving one reverse-VAT lookup (company name + address → VAT + confidence).
822
+ * Mirrors the API response item shape (camelCase keys).
823
+ */
824
+ declare class SmartEnrichmentResource {
825
+ readonly status: SmartEnrichmentStatus;
826
+ readonly vatNumber: string | undefined;
827
+ readonly vatType: string | undefined;
828
+ readonly confidence: number | undefined;
829
+ readonly matchedCompanyName: string | undefined;
830
+ /** Official/registered address of the matched company, when available. */
831
+ readonly matchedAddress: string | undefined;
832
+ readonly country: string | undefined;
833
+ readonly source: string | undefined;
834
+ /** The search mode this lookup actually ran in. */
835
+ readonly mode: SmartEnrichmentMode | undefined;
836
+ /**
837
+ * What each AI provider independently concluded. Populated when more than one searched
838
+ * (complex mode, or a fallback). Two entries reporting the same vatNumber is the strongest
839
+ * confirmation this layer produces.
840
+ */
841
+ readonly providerVerdicts: SmartEnrichmentProviderVerdict[];
842
+ readonly addressQuality: SmartEnrichmentAddressQuality | undefined;
843
+ constructor(status: SmartEnrichmentStatus, vatNumber: string | undefined, vatType: string | undefined, confidence: number | undefined, matchedCompanyName: string | undefined,
844
+ /** Official/registered address of the matched company, when available. */
845
+ matchedAddress: string | undefined, country: string | undefined, source: string | undefined,
846
+ /** The search mode this lookup actually ran in. */
847
+ mode?: SmartEnrichmentMode | undefined,
848
+ /**
849
+ * What each AI provider independently concluded. Populated when more than one searched
850
+ * (complex mode, or a fallback). Two entries reporting the same vatNumber is the strongest
851
+ * confirmation this layer produces.
852
+ */
853
+ providerVerdicts?: SmartEnrichmentProviderVerdict[], addressQuality?: SmartEnrichmentAddressQuality | undefined);
854
+ static fromArray(data: Record<string, unknown>): SmartEnrichmentResource;
855
+ toArray(): Record<string, unknown>;
856
+ }
857
+
858
+ /**
859
+ * A Smart Enrichment job — single lookup or bulk batch. Unifies the API's sync and async
860
+ * responses: a confident single lookup comes back already resolved (one result, status
861
+ * `found`); everything else comes back `processing` with a `jobId` to poll.
862
+ */
863
+ declare class SmartEnrichmentJob {
864
+ readonly jobId: string;
865
+ readonly status: SmartEnrichmentStatus;
866
+ readonly itemCount: number | undefined;
867
+ readonly completedCount: number | undefined;
868
+ readonly foundCount: number | undefined;
869
+ readonly results: SmartEnrichmentResource[];
870
+ constructor(jobId: string, status: SmartEnrichmentStatus, itemCount: number | undefined, completedCount: number | undefined, foundCount: number | undefined, results: SmartEnrichmentResource[]);
871
+ static fromArray(data: Record<string, unknown>): SmartEnrichmentJob;
872
+ isProcessing(): boolean;
873
+ /** Convenience for single lookups: the first (or only) result, if any. */
874
+ result(): SmartEnrichmentResource | undefined;
875
+ private static looksLikeItem;
876
+ }
877
+
878
+ /**
879
+ * Full first input of a history row (incl. street + postalCode) — everything that was
880
+ * queried, so a detail view needs no second fetch. `query` stays the compact summary.
881
+ */
882
+ interface SmartEnrichmentHistoryInput {
883
+ companyName: string | undefined;
884
+ street: string | undefined;
885
+ postalCode: string | undefined;
886
+ city: string | undefined;
887
+ country: string | undefined;
888
+ }
889
+ /**
890
+ * One row of Smart Enrichment lookup history (compact summary; full detail via getJob).
891
+ */
892
+ declare class SmartEnrichmentHistoryRow {
893
+ readonly jobId: string;
894
+ readonly status: SmartEnrichmentStatus;
895
+ readonly isBulk: boolean;
896
+ readonly itemCount: number;
897
+ readonly foundCount: number;
898
+ readonly queryCompanyName: string | undefined;
899
+ readonly queryCountry: string | undefined;
900
+ readonly queryCity: string | undefined;
901
+ readonly input: SmartEnrichmentHistoryInput | undefined;
902
+ readonly result: SmartEnrichmentResource | undefined;
903
+ readonly createdAt: string | undefined;
904
+ readonly finishedAt: string | undefined;
905
+ constructor(jobId: string, status: SmartEnrichmentStatus, isBulk: boolean, itemCount: number, foundCount: number, queryCompanyName: string | undefined, queryCountry: string | undefined, queryCity: string | undefined, input: SmartEnrichmentHistoryInput | undefined, result: SmartEnrichmentResource | undefined, createdAt: string | undefined, finishedAt: string | undefined);
906
+ static fromArray(data: Record<string, unknown>): SmartEnrichmentHistoryRow;
907
+ }
908
+
909
+ /**
910
+ * Account-wide history tiles — stable regardless of the current search/page filter.
911
+ */
912
+ interface SmartEnrichmentHistoryStats {
913
+ total: number;
914
+ found: number;
915
+ }
916
+ /**
917
+ * A paginated page of Smart Enrichment lookup history.
918
+ */
919
+ declare class SmartEnrichmentHistoryPage implements Iterable<SmartEnrichmentHistoryRow> {
920
+ readonly rows: SmartEnrichmentHistoryRow[];
921
+ readonly currentPage: number;
922
+ readonly perPage: number;
923
+ readonly total: number;
924
+ readonly lastPage: number;
925
+ readonly stats?: SmartEnrichmentHistoryStats | undefined;
926
+ constructor(rows: SmartEnrichmentHistoryRow[], currentPage: number, perPage: number, total: number, lastPage: number, stats?: SmartEnrichmentHistoryStats | undefined);
927
+ static fromResponse(payload: unknown): SmartEnrichmentHistoryPage;
928
+ [Symbol.iterator](): Iterator<SmartEnrichmentHistoryRow>;
929
+ get length(): number;
930
+ }
931
+
932
+ /**
933
+ * DTOs for the Smart Enrichment statistics endpoint
934
+ * (GET /smart-enrichment/statistics).
935
+ *
936
+ * Read-only aggregation over the company's lookups: headline totals, a time
937
+ * series and breakdowns by source, outcome and confidence band. The API
938
+ * defaults to the last 12 months and a monthly interval.
939
+ */
940
+ /** Time-series bucket size accepted by the statistics endpoint. */
941
+ type SmartEnrichmentStatisticsInterval = 'day' | 'week' | 'month';
942
+ interface SmartEnrichmentStatisticsRange {
943
+ dateFrom: string;
944
+ dateTo: string;
945
+ interval: string;
946
+ }
947
+ interface SmartEnrichmentStatisticsTotals {
948
+ jobs: number;
949
+ items: number;
950
+ found: number;
951
+ /** Share of items that resolved to a VAT number, 0–100. */
952
+ foundRate: number;
953
+ /** Average confidence of found items, 0–100. */
954
+ avgConfidence: number;
955
+ }
956
+ interface SmartEnrichmentTimeBucket {
957
+ /** Period key: "2026-01-15" (day), "2026-03" (ISO year-week) or "2026-01" (month). */
958
+ bucket: string;
959
+ jobs: number;
960
+ items: number;
961
+ found: number;
962
+ }
963
+ interface SmartEnrichmentSourceBreakdown {
964
+ source: string;
965
+ jobs: number;
966
+ found: number;
967
+ }
968
+ interface SmartEnrichmentOutcomeBreakdown {
969
+ outcome: string;
970
+ count: number;
971
+ }
972
+ interface SmartEnrichmentConfidenceBucket {
973
+ /** Confidence band: "high", "medium" or "low". */
974
+ bucket: string;
975
+ count: number;
976
+ }
977
+ declare class SmartEnrichmentStatistics {
978
+ readonly range: SmartEnrichmentStatisticsRange;
979
+ readonly totals: SmartEnrichmentStatisticsTotals;
980
+ readonly timeSeries: SmartEnrichmentTimeBucket[];
981
+ readonly bySource: SmartEnrichmentSourceBreakdown[];
982
+ readonly byOutcome: SmartEnrichmentOutcomeBreakdown[];
983
+ readonly confidenceBuckets: SmartEnrichmentConfidenceBucket[];
984
+ constructor(range: SmartEnrichmentStatisticsRange, totals: SmartEnrichmentStatisticsTotals, timeSeries: SmartEnrichmentTimeBucket[], bySource: SmartEnrichmentSourceBreakdown[], byOutcome: SmartEnrichmentOutcomeBreakdown[], confidenceBuckets: SmartEnrichmentConfidenceBucket[]);
985
+ static fromArray(data: Record<string, unknown>): SmartEnrichmentStatistics;
986
+ }
987
+
988
+ interface SmartEnrichmentInput {
989
+ companyName: string;
990
+ country: string;
991
+ street?: string;
992
+ postalCode?: string;
993
+ city?: string;
994
+ /**
995
+ * Search depth. Omit to use the server default (`default`). `complex` searches with two
996
+ * independent providers and cross-checks them — better hit rate, higher cost per lookup.
997
+ */
998
+ mode?: SmartEnrichmentMode;
999
+ }
1000
+ /** One recent monthly billing entry, exposed on the usage response for transparency. */
1001
+ interface SmartEnrichmentUsageHistoryEntry {
1002
+ /** Billing period, e.g. "2026-05". */
1003
+ period: string;
1004
+ matches: number;
1005
+ /** Amount due for the period as a decimal string, e.g. "9.60". */
1006
+ amount: string;
1007
+ state: 'billed' | 'pending';
1008
+ billingType: string | null;
1009
+ manualReference: string | null;
1010
+ }
1011
+ interface SmartEnrichmentUsage {
1012
+ period: string;
1013
+ used: number;
1014
+ included: number;
1015
+ remaining: number;
1016
+ overageCount: number;
1017
+ overagePrice: number;
1018
+ overageAmount: number;
1019
+ hardCap: number | null;
1020
+ /** Recent monthly billing entries; empty when the API sends none. */
1021
+ history: SmartEnrichmentUsageHistoryEntry[];
1022
+ }
1023
+ interface SmartEnrichmentExportOptions {
1024
+ /** Inclusive lower bound on the job's creation date (YYYY-MM-DD). */
1025
+ dateFrom?: string;
1026
+ /** Inclusive upper bound on the job's creation date (YYYY-MM-DD). */
1027
+ dateTo?: string;
1028
+ /** Only include rows with at least this result confidence (0–100). */
1029
+ minConfidence?: number;
1030
+ /** Only include rows with one of these item statuses (found, no_vat_exists, not_found). */
1031
+ status?: SmartEnrichmentStatus[];
1032
+ /** Only include rows that resolved to a VAT number. */
1033
+ onlyFound?: boolean;
1034
+ }
1035
+ interface SmartEnrichmentStatisticsOptions {
1036
+ /** Inclusive lower bound (YYYY-MM-DD). Defaults to 12 months ago (server-side). */
1037
+ dateFrom?: string;
1038
+ /** Inclusive upper bound (YYYY-MM-DD). Defaults to today (server-side). */
1039
+ dateTo?: string;
1040
+ /** Time-series bucket size. Defaults to "month" server-side. */
1041
+ interval?: SmartEnrichmentStatisticsInterval;
1042
+ }
1043
+ interface SmartEnrichmentWaitOptions {
1044
+ /** Delay between polls in milliseconds. Defaults to 2000. */
1045
+ pollIntervalMs?: number;
1046
+ /** Maximum total time to wait in milliseconds. Defaults to 120000. */
1047
+ timeoutMs?: number;
1048
+ }
1049
+ /**
1050
+ * Smart Enrichment — reverse VAT lookup (company name + address + country → VAT + confidence).
1051
+ *
1052
+ * let job = await client.smartEnrichment.lookup({ companyName: 'Example GmbH', country: 'AT' });
1053
+ * if (job.isProcessing()) job = await client.smartEnrichment.waitForCompletion(job.jobId);
1054
+ * console.log(job.result()?.vatNumber);
1055
+ */
1056
+ declare class SmartEnrichmentEndpoint {
1057
+ private readonly baseUrl;
1058
+ private readonly apiKey;
1059
+ private readonly tokenStorage;
1060
+ private readonly httpClient;
1061
+ private readonly retryPolicy;
1062
+ constructor(baseUrl: string, apiKey: string, tokenStorage: TokenStorageInterface, httpClient: HttpClientInterface, retryPolicy?: RetryPolicy);
1063
+ /**
1064
+ * Single reverse lookup. Returns a confident result synchronously, or a `processing`
1065
+ * job (poll with get(job.jobId) or waitForCompletion(job.jobId)) when deeper resolution
1066
+ * is needed.
1067
+ */
1068
+ lookup(input: SmartEnrichmentInput): Promise<SmartEnrichmentJob>;
1069
+ /**
1070
+ * Bulk batch — always async. Returns a `processing` job; results arrive via the
1071
+ * `enrichment.completed` webhook and are retrievable via get(job.jobId).
1072
+ *
1073
+ * @param mode Search depth for every row in the batch. A row carrying its own `mode` overrides
1074
+ * it, so a caller can pay for `complex` on just the rows that need it.
1075
+ */
1076
+ bulkLookup(items: SmartEnrichmentInput[], mode?: SmartEnrichmentMode): Promise<SmartEnrichmentJob>;
1077
+ /** Poll a job (single or bulk) by its id. */
1078
+ get(jobId: string): Promise<SmartEnrichmentJob>;
1079
+ /**
1080
+ * Poll get(jobId) until the job is no longer processing (completed, failed or resolved).
1081
+ * Throws a TaxoraException when the job does not finish within `timeoutMs`.
1082
+ */
1083
+ waitForCompletion(jobId: string, options?: SmartEnrichmentWaitOptions): Promise<SmartEnrichmentJob>;
1084
+ /**
1085
+ * Paginated lookup history (newest first). `perPage` is capped at 100 server-side.
1086
+ * `search` filters (free-text) over the queried company name and the resolved
1087
+ * VAT number / matched company name.
1088
+ */
1089
+ history(page?: number, perPage?: number, search?: string): Promise<SmartEnrichmentHistoryPage>;
1090
+ /** Current billing-period quota usage, plus recent monthly billing entries. */
1091
+ usage(): Promise<SmartEnrichmentUsage>;
1092
+ /**
1093
+ * Export the company's lookups as CSV (bulk-input shape plus the resolved VAT columns;
1094
+ * bulk jobs are flattened to one line per input row). Returns the raw CSV text
1095
+ * (UTF-8, BOM included by the API so Excel opens umlauts correctly).
1096
+ */
1097
+ export(options?: SmartEnrichmentExportOptions): Promise<string>;
1098
+ /**
1099
+ * Aggregated lookup statistics: headline totals, a time series and breakdowns by
1100
+ * source, outcome and confidence band. The API defaults to the last 12 months
1101
+ * and a monthly interval.
1102
+ */
1103
+ statistics(options?: SmartEnrichmentStatisticsOptions): Promise<SmartEnrichmentStatistics>;
1104
+ private validateInput;
1105
+ private validateJobId;
1106
+ private buildHeaders;
1107
+ private sendRequest;
1108
+ private parseJsonResponse;
1109
+ /**
1110
+ * Like parseJsonResponse but returns the whole object WITHOUT unwrapping `data` — used for
1111
+ * the paginated history response (where `data` is the row array and `meta`/`stats` must be
1112
+ * preserved) and the statistics response.
1113
+ */
1114
+ private parseRawJson;
1115
+ /**
1116
+ * For the CSV export: keeps the shared 422/HTTP error mapping but returns the body
1117
+ * verbatim (text/csv) instead of parsing JSON.
1118
+ */
1119
+ private parseCsvResponse;
1120
+ private parseValidationErrors;
1121
+ private parseUsageHistory;
1122
+ }
1123
+
76
1124
  declare const VatState: {
77
1125
  readonly VALID: "valid";
78
1126
  readonly INVALID: "invalid";
@@ -241,9 +1289,9 @@ declare class VatEndpoint {
241
1289
  private readonly apiKey;
242
1290
  private readonly tokenStorage;
243
1291
  private readonly httpClient;
244
- constructor(baseUrl: string, apiKey: string, tokenStorage: TokenStorageInterface, httpClient: HttpClientInterface);
1292
+ private readonly retryPolicy;
1293
+ constructor(baseUrl: string, apiKey: string, tokenStorage: TokenStorageInterface, httpClient: HttpClientInterface, retryPolicy?: RetryPolicy);
245
1294
  validate(vatUid: string, companyName?: string, provider?: string, addressInput?: VatValidationAddressInput | Record<string, string>): Promise<VatResource>;
246
- private validateWithGatewayRetry;
247
1295
  validateMultiple(vatUids: string[], companyNames?: string[], provider?: string): Promise<VatCollection>;
248
1296
  validateSchema(vatUid: string): Promise<Record<string, unknown>>;
249
1297
  state(vatUid: string): Promise<VatResource>;
@@ -273,11 +1321,15 @@ interface TaxoraClientOptions {
273
1321
  environment?: Environment;
274
1322
  tokenStorage?: TokenStorageInterface;
275
1323
  httpClient?: HttpClientInterface;
1324
+ /** Retry behaviour for transient gateway failures; defaults to 3 attempts with backoff. */
1325
+ retryPolicy?: RetryPolicy;
276
1326
  }
277
1327
  declare class TaxoraClient {
278
1328
  readonly auth: AuthEndpoint;
279
1329
  readonly vat: VatEndpoint;
280
1330
  readonly company: CompanyEndpoint;
1331
+ readonly smartEnrichment: SmartEnrichmentEndpoint;
1332
+ readonly eReporting: EReportingEndpoint;
281
1333
  readonly baseUrl: string;
282
1334
  constructor(options: TaxoraClientOptions);
283
1335
  }
@@ -304,9 +1356,17 @@ declare class AuthenticationException extends TaxoraException {
304
1356
  declare class HttpException extends TaxoraException {
305
1357
  readonly statusCode: number;
306
1358
  readonly responseBody: string;
307
- constructor(message: string, statusCode: number, responseBody: string, context?: Record<string, unknown>);
1359
+ /** Raw `Retry-After` header of the failed response, when it carried one. */
1360
+ readonly retryAfter: string | null;
1361
+ constructor(message: string, statusCode: number, responseBody: string, context?: Record<string, unknown>, retryAfter?: string | null);
1362
+ /**
1363
+ * The final failure after the SDK retried a transient gateway error, e.g.
1364
+ * "Taxora VAT validation failed after 3 attempts (HTTP 504 Gateway Timeout)."
1365
+ */
1366
+ static afterAttempts(operation: string, attempts: number, last: HttpException): HttpException;
308
1367
  getStatusCode(): number;
309
1368
  getResponseBody(): string;
1369
+ getRetryAfter(): string | null;
310
1370
  }
311
1371
 
312
1372
  declare class ValidationException extends TaxoraException {
@@ -316,6 +1376,24 @@ declare class ValidationException extends TaxoraException {
316
1376
  getErrors(): Record<string, string[]>;
317
1377
  }
318
1378
 
1379
+ /**
1380
+ * Derives a short, human readable exception message from an API response body.
1381
+ *
1382
+ * A response body is never used verbatim as an exception message: the gateways
1383
+ * in front of the API (DigitalOcean App Platform, load balancers, proxies)
1384
+ * answer 5xx with a full HTML error page, and that page would otherwise end up
1385
+ * in every log line and stack trace of the integrating application.
1386
+ *
1387
+ * Only the human readable message of a JSON error body is used; everything else
1388
+ * (HTML, empty bodies, binary payloads) falls back to the HTTP status line. The
1389
+ * untouched body always stays available via `HttpException.getResponseBody()`.
1390
+ */
1391
+ /**
1392
+ * The message for a failed request: the API message when the body carries one,
1393
+ * otherwise a description of the HTTP status.
1394
+ */
1395
+ declare function describeApiError(body: string | null | undefined, statusCode: number): string;
1396
+
319
1397
  declare class InMemoryTokenStorage implements TokenStorageInterface {
320
1398
  private token;
321
1399
  get(): Token | null;
@@ -342,4 +1420,4 @@ declare class AuthRetryHttpClient implements HttpClientInterface {
342
1420
  private injectAuthHeader;
343
1421
  }
344
1422
 
345
- export { ApiVersion, AuthEndpoint, AuthRetryHttpClient, AuthenticationException, CompanyAddress, CompanyEndpoint, type CompanyResource, Environment, Environment as EnvironmentType, FetchHttpClient, type HttpClientInterface, HttpException, InMemoryTokenStorage, Language, LoginIdentifier, ProviderDocument, ProviderDocumentLine, ScoreBreakdown, TaxoraClient, TaxoraClientFactory, type TaxoraClientOptions, TaxoraException, Token, type TokenStorageInterface, ValidationException, VatCertificateExport, VatCollection, VatEndpoint, VatResource, VatState, VatValidationAddressInput, describeVatState, getBaseUrl, getFailedVatStates };
1423
+ export { ApiVersion, AuthEndpoint, AuthRetryHttpClient, AuthenticationException, CompanyAddress, CompanyEndpoint, type CompanyResource, ComplianceEnrollment, ComplianceEnrollmentPage, ComplianceEnrollmentStatus, type ComplianceEnterpriseSize, type ComplianceInvoiceLineInput, type ComplianceInvoiceTaxInput, ComplianceTaxReport, ComplianceTaxReportPage, type ComplianceTaxReportRequestState, ComplianceTaxReportState, ComplianceTransaction, type ComplianceTransactionFilters, ComplianceTransactionPage, type ComplianceTransactionRequestState, type ComplianceTransactionRequestType, ComplianceTransactionState, ComplianceTransactionType, type ComplianceTypeOperation, type CreateComplianceEnrollmentInput, type CreateComplianceTransactionInput, type EReportingAccessRequestInput, EReportingEndpoint, type EReportingInterval, Environment, Environment as EnvironmentType, FetchHttpClient, type HttpClientInterface, HttpException, ImportResult, InMemoryTokenStorage, Language, LoginIdentifier, ProviderDocument, ProviderDocumentLine, RetryPolicy, type RetryPolicyOptions, type RevenueCountryBreakdown, type RevenueCurrencyBreakdown, type RevenueStateBreakdown, RevenueStatistics, type RevenueStatisticsFilters, type RevenueTimeBucket, type RevenueTotals, type RevenueTypeBreakdown, ScoreBreakdown, SireneLookupResult, type SmartEnrichmentAddressQuality, type SmartEnrichmentConfidenceBucket, SmartEnrichmentEndpoint, type SmartEnrichmentExportOptions, type SmartEnrichmentHistoryInput, SmartEnrichmentHistoryPage, SmartEnrichmentHistoryRow, type SmartEnrichmentHistoryStats, type SmartEnrichmentInput, SmartEnrichmentJob, SmartEnrichmentMode, type SmartEnrichmentOutcomeBreakdown, type SmartEnrichmentProviderVerdict, SmartEnrichmentResource, type SmartEnrichmentSourceBreakdown, SmartEnrichmentStatistics, type SmartEnrichmentStatisticsInterval, type SmartEnrichmentStatisticsOptions, type SmartEnrichmentStatisticsRange, type SmartEnrichmentStatisticsTotals, SmartEnrichmentStatus, type SmartEnrichmentTimeBucket, type SmartEnrichmentUsage, type SmartEnrichmentUsageHistoryEntry, type SmartEnrichmentWaitOptions, TaxoraClient, TaxoraClientFactory, type TaxoraClientOptions, TaxoraException, Token, type TokenStorageInterface, type UpdateComplianceTransactionInput, ValidationException, VatCertificateExport, VatCollection, VatEndpoint, type VatRate, VatRates, VatResource, VatState, VatValidationAddressInput, describeApiError, describeComplianceEnrollmentStatus, describeComplianceTaxReportState, describeComplianceTransactionState, describeComplianceTransactionType, describeSmartEnrichmentMode, describeSmartEnrichmentStatus, describeVatState, getBaseUrl, getFailedVatStates, toComplianceEnrollmentStatus, toComplianceTaxReportState, toComplianceTransactionState, toComplianceTransactionType, toSmartEnrichmentMode, toSmartEnrichmentStatus };