@taxora/sdk 1.1.0 → 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/README.md +91 -1
- package/dist/index.cjs +524 -126
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +188 -10
- package/dist/index.d.ts +188 -10
- package/dist/index.js +519 -126
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -331,7 +331,35 @@ console.log(result?.status); // 'found' | 'no_vat_exists' | 'not_found'
|
|
|
331
331
|
console.log(result?.vatNumber); // e.g. 'ATU12345678'
|
|
332
332
|
console.log(result?.confidence); // 0–100
|
|
333
333
|
|
|
334
|
+
// Search mode: 'default' searches with one AI provider and only consults a second one when
|
|
335
|
+
// the first finds nothing. 'complex' has two independent providers search from the start and
|
|
336
|
+
// puts every number either of them proposes through the tax authority's checks. Complex finds
|
|
337
|
+
// companies a single search misses — typically ones whose VAT only appears in a website
|
|
338
|
+
// Impressum — and costs more per lookup, so it is opt-in.
|
|
339
|
+
const deep = await client.smartEnrichment.lookup({
|
|
340
|
+
companyName: 'Vodafone D2 GmbH',
|
|
341
|
+
country: 'DE',
|
|
342
|
+
postalCode: '40547',
|
|
343
|
+
mode: SmartEnrichmentMode.COMPLEX,
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// When more than one provider searched, you can see what each one concluded on its own.
|
|
347
|
+
// Two of them reporting the same number is the strongest confirmation this layer produces.
|
|
348
|
+
for (const verdict of deep.result()?.providerVerdicts ?? []) {
|
|
349
|
+
console.log(`${verdict.provider}: ${verdict.vatNumber ?? 'nothing'}`);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// The API also grades the address you sent. Worth writing back into your own records: a
|
|
353
|
+
// 'postal_code_city_mismatch' / 'postal_code_unassigned' warning means the postal code in
|
|
354
|
+
// your source data is wrong, and `derivedPlace` is the area it actually points at.
|
|
355
|
+
const quality = deep.result()?.addressQuality;
|
|
356
|
+
if (quality && quality.warnings.length > 0) {
|
|
357
|
+
console.log(quality.warnings.join(', '), '→', quality.derivedPlace);
|
|
358
|
+
}
|
|
359
|
+
|
|
334
360
|
// Bulk lookup (always async → webhook + polling)
|
|
361
|
+
// The batch-level mode applies to every row; a row carrying its own `mode` overrides it,
|
|
362
|
+
// so you can pay for 'complex' on just the rows that need it.
|
|
335
363
|
const bulk = await client.smartEnrichment.bulkLookup([
|
|
336
364
|
{ companyName: 'A GmbH', country: 'DE', city: 'Berlin' },
|
|
337
365
|
{ companyName: 'B SARL', country: 'FR' },
|
|
@@ -668,11 +696,73 @@ try {
|
|
|
668
696
|
console.error('Validation errors:', err.getErrors()); // Record<string, string[]>
|
|
669
697
|
} else if (err instanceof HttpException) {
|
|
670
698
|
// Any other HTTP error
|
|
671
|
-
console.error(`HTTP ${err.getStatusCode()}:`, err.
|
|
699
|
+
console.error(`HTTP ${err.getStatusCode()}:`, err.message);
|
|
672
700
|
}
|
|
673
701
|
}
|
|
674
702
|
```
|
|
675
703
|
|
|
704
|
+
**Exception messages are always short and safe to log.** A response body is
|
|
705
|
+
never used as the message: gateways in front of the API answer `502`/`503`/`504`
|
|
706
|
+
with a full HTML error page, and that page would otherwise land in every log
|
|
707
|
+
line of your application. The SDK uses the `message` / `error` field of a JSON
|
|
708
|
+
error body when there is one, and falls back to the status line
|
|
709
|
+
(`Taxora API request failed (HTTP 504 Gateway Timeout).`) otherwise. The
|
|
710
|
+
untouched body stays available via `err.getResponseBody()`.
|
|
711
|
+
|
|
712
|
+
### Automatic retries
|
|
713
|
+
|
|
714
|
+
The SDK retries what never produced an answer from the API itself: **3 attempts,
|
|
715
|
+
with 500 ms and 1000 ms of backoff in between**. That covers
|
|
716
|
+
|
|
717
|
+
- **gateway failures (`502`, `503`, `504`)** — the infrastructure in front of the
|
|
718
|
+
API, where a second attempt a moment later usually succeeds;
|
|
719
|
+
- **connection-level failures** — reset connections, client-side timeouts, DNS
|
|
720
|
+
hiccups (`fetch failed`, `ECONNRESET`, `UND_ERR_CONNECT_TIMEOUT`, …). Once the
|
|
721
|
+
attempts are used up, the original error is rethrown unchanged;
|
|
722
|
+
- **`429 Too Many Requests`, but only with a `Retry-After`** — then the SDK waits
|
|
723
|
+
exactly as long as the API asked instead of using its own backoff. Without that
|
|
724
|
+
header a retry would only hammer a rate limit that is already tripped, so the
|
|
725
|
+
error is surfaced immediately. A `Retry-After` longer than `maxRetryAfterMs`
|
|
726
|
+
(10 s by default) also fails immediately rather than blocking your worker — the
|
|
727
|
+
raw header stays readable via `err.getRetryAfter()`.
|
|
728
|
+
|
|
729
|
+
Everything else fails on the first attempt, including any `5xx` the API produced
|
|
730
|
+
itself (a `500` is a bug, not a hiccup — repeating it just costs time).
|
|
731
|
+
|
|
732
|
+
Retries apply to read-only calls only — VAT validation, lookups, state, history,
|
|
733
|
+
search, certificate downloads, company and e-reporting reads, login and token
|
|
734
|
+
refresh. Calls that change state or cost quota (`certificatesBulkExport()`,
|
|
735
|
+
`smartEnrichment.lookup()`, e-reporting enrollment/transaction writes) are
|
|
736
|
+
**never** retried automatically, because a gateway timeout does not tell us
|
|
737
|
+
whether the API already processed the request.
|
|
738
|
+
|
|
739
|
+
Once the attempts are used up you get one clean error:
|
|
740
|
+
|
|
741
|
+
```
|
|
742
|
+
Taxora VAT validation failed after 3 attempts (HTTP 504 Gateway Timeout).
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
Tune or disable it via `RetryPolicy`:
|
|
746
|
+
|
|
747
|
+
```ts
|
|
748
|
+
import { RetryPolicy, TaxoraClientFactory } from '@taxora/sdk';
|
|
749
|
+
|
|
750
|
+
const client = TaxoraClientFactory.create({
|
|
751
|
+
apiKey: 'YOUR_X_API_KEY',
|
|
752
|
+
retryPolicy: new RetryPolicy({
|
|
753
|
+
maxAttempts: 5,
|
|
754
|
+
initialDelayMs: 250,
|
|
755
|
+
retryableStatusCodes: [502, 503, 504], // add or drop status codes
|
|
756
|
+
respectRetryAfter: true, // false = ignore the header entirely
|
|
757
|
+
maxRetryAfterMs: 10_000, // longest wait accepted from Retry-After
|
|
758
|
+
retryOnNetworkErrors: true, // false = surface transport errors at once
|
|
759
|
+
}),
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
// or, for callers that do their own retrying (queue workers, cron jobs):
|
|
763
|
+
const noRetries = TaxoraClientFactory.create({ apiKey: '…', retryPolicy: RetryPolicy.disabled() });
|
|
764
|
+
```
|
|
765
|
+
|
|
676
766
|
---
|
|
677
767
|
|
|
678
768
|
## 🔌 VatState Helpers
|