Package Exports
- @taxora/sdk
Readme
@taxora/sdk
Official Node.js/TypeScript SDK for the Taxora VAT Validation API Validate EU VAT numbers, generate compliance certificates, and integrate VAT checks into your Node.js services โ with clean, modern TypeScript and zero runtime dependencies.
๐ Overview
The Taxora SDK provides a clean, type-safe interface to the Taxora API, supporting:
- โ Secure API-Key and Bearer Token authentication with auto-refresh
- โ Single & multiple VAT validation with AI-based company name matching
- โ VAT state history and full-text search endpoints
- โ Certificate generation (PDF) and bulk/list exports (ZIP or PDF)
- โ
Strict TypeScript โ full type coverage, zero
any - โ
Native
fetch(Node 18+) โ zero runtime dependencies - โ Dual ESM + CJS output for maximum compatibility
๐ The SDK itself is free to use, but a Taxora API subscription is required. Obtain your
x-api-keyfrom your Taxora account developer settings.
๐งฎ Installation
npm install @taxora/sdkRequirements: Node.js โฅ 18 (uses native fetch โ no polyfill needed)
โ๏ธ Quick Start
import { TaxoraClientFactory, Environment } from '@taxora/sdk';
const client = TaxoraClientFactory.create({
apiKey: 'YOUR_X_API_KEY',
environment: Environment.SANDBOX, // or Environment.PRODUCTION
});
// 1๏ธโฃ Authenticate
await client.auth.login('user@example.com', 'superSecret');
// 2๏ธโฃ Validate a VAT number
const vat = await client.vat.validate('ATU12345678', 'Example GmbH');
console.log(vat.state); // 'valid' | 'invalid' | 'fraud' | 'unknown'
console.log(vat.companyName); // Official company name from registry
console.log(vat.score); // Overall confidence score (0.0 โ 1.0)
for (const step of vat.breakdown ?? []) {
console.log(`${step.stepName} โ ${step.scoreContribution}`);
}
// Optional: typed address input for fallback name scoring
import { VatValidationAddressInput } from '@taxora/sdk';
const addressInput = new VatValidationAddressInput({
addressLine1: 'Ringstraรe 1',
postalCode: '1010',
city: 'Vienna',
countryCode: 'AT',
});
const vatWithAddress = await client.vat.validate('ATU12345678', 'Example GmbH', 'vies', addressInput);
// 3๏ธโฃ Access company context
const company = await client.company.get();
// 4๏ธโฃ Export certificates
const exportJob = await client.vat.certificatesBulkExport('2024-01-01', '2024-12-31');
const zip = await client.vat.downloadBulkExport(exportJob.exportId);
import { writeFileSync } from 'fs';
writeFileSync('certificates.zip', zip);vat.validate() returns a VatResource with the canonical VAT UID, status, company data, and optional scoring details. The score reflects overall confidence (higher is better), while breakdown is an array of ScoreBreakdown objects describing each validation step, its score contribution, and metadata (e.g. matched addresses or mismatched fields).
Need a custom HTTP client (e.g. for logging or retries)? Pass it via the factory:
import { TaxoraClientFactory, HttpClientInterface } from '@taxora/sdk';
class LoggingHttpClient implements HttpClientInterface {
async request(method: string, url: string, options?: RequestInit): Promise<Response> {
console.log(`โ ${method} ${url}`);
return fetch(url, { ...options, method });
}
}
const client = TaxoraClientFactory.create({
apiKey: 'YOUR_X_API_KEY',
httpClient: new LoggingHttpClient(),
});๐งฉ Architecture
The SDK follows clean separation of concerns:
TaxoraClientFactory.create()
โโโ TaxoraClient
โโโ auth โ AuthEndpoint (login, loginWithClientId, refresh)
โโโ vat โ VatEndpoint (validate, history, search, certificates)
โโโ company โ CompanyEndpoint (company info)Each endpoint handles:
- Request signing with
x-api-key - Bearer token injection and proactive refresh if expired
- JSON/binary response parsing into typed DTOs
VatEndpoint and CompanyEndpoint use the AuthRetryHttpClient wrapper, which transparently handles preemptive token refresh and 401 retry โ AuthEndpoint always uses the raw HTTP client to avoid circular refresh calls.
๐ฆ DTOs
| Class | Description |
|---|---|
VatResource |
Single VAT validation result: state, score, breakdown, company name, address, provider document |
VatCollection |
Iterable collection of VatResource objects with optional pagination self link |
ScoreBreakdown |
Per-step scoring fragment: step name, score contribution, and metadata context |
CompanyAddress |
Structured company address; assembles fullAddress from components or parses JSON strings |
VatValidationAddressInput |
Typed input for address-based fallback scoring (validates lengths, country code format) |
Token |
Access token with type and expiry; 15-second buffer for proactive refresh |
VatCertificateExport |
Bulk export job reference (exportId + optional message) |
ProviderDocument |
Attached provider document metadata (type, date, MIME, hash, nested line item) |
All DTOs expose toArray() for serialization and a static fromArray() factory.
const dto = await client.vat.validate('ATU12345678');
console.log(dto.toArray());๐ Authentication Flow
1. Login
// Email + password
await client.auth.login('user@example.com', 'password', 'my-server-01');
// device_name is optional; omitted value falls back to os.hostname()
// Client ID + secret
await client.auth.loginWithClientId('client_abc123', 'client-secret', 'integration-box');
// Explicit identifier enum
import { LoginIdentifier } from '@taxora/sdk';
await client.auth.login('client_abc123', 'client-secret', undefined, LoginIdentifier.CLIENT_ID);โ Stores and returns a Token DTO (valid for ~3600 seconds).
2. Auto-refresh
The SDK automatically refreshes the token in two scenarios:
| Trigger | Behaviour |
|---|---|
| Preemptive (token expired + 15 s buffer) | Refreshes before the next request |
Reactive (API returns 401) |
Refreshes once and retries the original request |
You never need to call refresh() manually in normal usage.
3. Manual refresh
await client.auth.refresh();4. Custom token storage
By default, tokens are stored in-memory and lost on process restart. Provide your own storage for persistence:
import { TokenStorageInterface, Token } from '@taxora/sdk';
class RedisTokenStorage implements TokenStorageInterface {
get(): Token | null {
/* read from Redis */ return null;
}
set(token: Token): void {
/* write with TTL = token.expiresAt */
}
clear(): void {
/* delete key */
}
}
const client = TaxoraClientFactory.create({
apiKey: 'YOUR_X_API_KEY',
tokenStorage: new RedisTokenStorage(),
});๐งพ VAT Validation
Single Validation
// Basic โ state only
const vat = await client.vat.validate('ATU12345678');
// With company name matching
const vat = await client.vat.validate('ATU12345678', 'Alpha Handels GmbH');
// With address input for enhanced score
const vat = await client.vat.validate('ATU12345678', 'Alpha Handels GmbH', 'vies', {
address_line_1: 'Ringstraรe 1',
postal_code: '1010',
city: 'Wien',
country_code: 'AT',
});
console.log(vat.state); // VatState value
console.log(vat.score); // 0.0 โ 1.0
console.log(vat.companyAddress?.toString()); // Full address string
console.log(vat.getBackendLink()); // https://app.taxora.io/vat/history/{uuid}Schema Validation (format check only)
const result = await client.vat.validateSchema('ATU12345678');Batch Validation
const collection = await client.vat.validateMultiple(
['ATU12345678', 'DE123456789'],
['Alpha Handels GmbH', 'Beta Technik GmbH'],
);
for (const vat of collection) {
console.log(vat.vatUid, vat.state);
}
console.log(collection.length); // 2VAT State Snapshot
const vat = await client.vat.state('ATU12345678');History
const history = await client.vat.history(); // all entries
const history = await client.vat.history('ATU12345678'); // filtered
for (const entry of history) {
console.log(entry.checkedAt, entry.state);
}Search
const results = await client.vat.search('Alpha Handels', 25 /* perPage */);๐ Certificates
Single Certificate (PDF)
import { Language } from '@taxora/sdk';
import { writeFileSync } from 'fs';
const pdf = await client.vat.certificate('uuid-123', Language.GERMAN);
writeFileSync('certificate.pdf', pdf);Bulk Export (ZIP)
const exportJob = await client.vat.certificatesBulkExport(
'2024-01-01', // or new Date('2024-01-01')
'2024-12-31',
['AT', 'DE'], // optional: filter by country
Language.ENGLISH, // optional: language
);
console.log(exportJob.exportId); // poll or use directly
const zip = await client.vat.downloadBulkExport(exportJob.exportId);
writeFileSync('certificates.zip', zip);List Export
const exportJob = await client.vat.certificatesListExport(new Date('2024-01-01'), new Date('2024-12-31'));๐ Environments
| Environment | Base URL |
|---|---|
Environment.SANDBOX |
https://sandbox.taxora.io/v1 |
Environment.PRODUCTION |
https://api.taxora.io/v1 |
const client = TaxoraClientFactory.create({
apiKey: 'YOUR_X_API_KEY',
environment: Environment.PRODUCTION,
});Need sandbox sample data? Known VAT UIDs with deterministic responses live in tests/fixtures/SandboxVatFixtures.ts.
โ ๏ธ Error Handling
import { AuthenticationException, HttpException, ValidationException } from '@taxora/sdk';
try {
await client.vat.validate('ATU12345678');
} catch (err) {
if (err instanceof AuthenticationException) {
// HTTP 401 โ credentials invalid or token refresh failed
console.error('Auth failed:', err.message);
} else if (err instanceof ValidationException) {
// HTTP 422 โ request payload rejected by the API
console.error('Validation errors:', err.getErrors()); // Record<string, string[]>
} else if (err instanceof HttpException) {
// Any other HTTP error
console.error(`HTTP ${err.getStatusCode()}:`, err.getResponseBody());
}
}๐ VatState Helpers
import { VatState, getFailedVatStates, describeVatState } from '@taxora/sdk';
VatState.VALID; // 'valid'
VatState.INVALID; // 'invalid'
VatState.FRAUD; // 'fraud'
VatState.UNKNOWN; // 'unknown'
getFailedVatStates(); // ['invalid', 'fraud']
describeVatState(VatState.VALID); // 'The VAT number is valid and active.'๐งช Testing
npm test # Run all 129 tests
npm run test:coverage # Run with v8 coverage report
npm run test:watch # Watch mode during developmentCI runs on Node 18, 20, and 22, verifying:
- 129 Vitest unit tests across 18 test files
- 97.8 % statement coverage / 87 % branch coverage / 100 % function coverage
- Strict TypeScript compilation
๐๏ธ Build
npm run build
# โ dist/index.js (ESM)
# โ dist/index.cjs (CommonJS)
# โ dist/index.d.ts (TypeScript declarations)โ ๏ธ Deprecations
So fresh there aren't even any deprecated features yet. Check back in a few months when we're on v47 and have made some regrettable decisions. ๐
๐ชช License
Licensed under the MIT License ยฉ 2025 theconcept technologies. The SDK is open-source, but API usage requires a valid Taxora subscription.
๐ค Contributing
Contributions and pull requests are welcome!
- Follow the existing TypeScript code style (strict mode, no
any). - Run
npm testbefore submitting a PR. - Ensure new endpoints include DTOs + tests.
๐ฌ Support
Need help or enterprise support? ๐ง support@taxora.io ๐ https://taxora.io