npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

evatr-api

v0.3.0

Published

Checks a VAT-ID using the eVatR REST-API of the German Federal Central Tax Office (Bundeszentralamt für Steuern, BZSt)

Readme

Recht logisch eVatR banner image

Tests codecov NPM Version

evatr-api

Checks a VAT-ID using the eVatR REST-API of the German Federal Central Tax Office (Bundeszentralamt für Steuern, BZSt)

[!CAUTION] This package is in early development and is not yet ready for production use. It is currently being tested and may undergo significant changes.

[!IMPORTANT] This is an unofficial wrapper for the eVatR API. For official documentation and terms of use, please refer to the German Federal Central Tax Office (BZSt) website.

[!NOTE] This package uses the new REST-API released in July 2025. The old XML-RPC API is being discontinued and will be sunset on November 30th, 2025 (based on information from BZSt-Newsletter USTKV 01/2025 dated July 1st, 2025).

Installation

You can install the package via npm:

npm install evatr-api

Quick Start

import { EvatrClient } from 'evatr-api';

const client = new EvatrClient();

// Simple validation (only checks if VAT-ID is valid)
const result = await client.validateSimple({
  vatIdOwn: 'DE123456789',
  vatIdForeign: 'ATU12345678'
});

console.log(result);

or

// Qualified validation with company data
const result = await client.validateQualified({
  vatIdOwn: 'DE123456789',
  vatIdForeign: 'ATU12345678',
  company: 'Musterhaus GmbH & Co KG',
  location: 'musterort'
});

console.log(result);

[!TIP] You might want to take a look at some examples.

Status Codes

The API returns various status codes. You can check the status using the client methods:

const result = await client.validateSimple({ /* ... */ });

client.isSuccessStatus(result.status);  // true for valid VAT-IDs
client.isErrorStatus(result.status);    // true for errors
client.isWarningStatus(result.status);  // true for warnings

// Get human-readable message
const message = client.getStatusMessage(result.status);
console.log(message?.message); // Message in German

API Reference

Constructor

const client = new EvatrClient(config?: EvatrClientConfig);

Configuration Options:

  • timeout?: number - Request timeout in milliseconds (default: 30000 ms; = 30 s)
  • headers?: Record<string, string> - Custom headers to include with requests

Methods

Simple Validation

Validates only the VAT-ID without company data verification:

await client.validateSimple({
  vatIdOwn: 'DE123456789',     // Your German VAT-ID (required)
  vatIdForeign: 'ATU12345678', // VAT-ID to validate (required)
  includeRaw: true,            // Include raw response (optional)
});

Qualified Validation

Validates VAT-ID and verifies company data:

await client.validateQualified({
  vatIdOwn: 'DE123456789',            // Your German VAT-ID (required)
  vatIdForeign: 'ATU12345678',        // VAT-ID to validate (required)
  company: 'Musterhaus GmbH & Co KG', // Company name (required)
  location: 'musterort',              // City (required)
  street: 'Musterstrasse 22',         // Street address (optional)
  zip: '12345',                       // Postal code (optional)
  includeRaw: true,                   // Include raw response (optional)
});

[!TIP] You may set true as the second parameter to get an ExtendedResponse object.

Utility Methods

// Get status messages
const statusMessages = await client.getStatusMessages();

// Get availability map by EU member state (alpha-2 code -> boolean)
const availability = await client.getAvailability();
const isGermanyAvailable = availability.DE === true;

// Get content of specific status message
const message = client.getStatusMessage('evatr-0000');

// Check status types
client.isSuccessStatus('evatr-0000'); // true
client.isErrorStatus('evatr-0004');   // true
client.isWarningStatus('evatr-2002'); // true

Request

The API uses German terms, which have been mapped to the following English parameters:

| BZSt API | evatr-api | |-------------------|----------------| | anfragendeUstid | vatIdOwn | | angefragteUstid | vatIdForeign | | firmenname | company | | ort | location | | strasse | street | | plz | zip |

Response

All validation methods return a Response object by default:

interface Response {
  id: string;                // Technical request ID returned by the API, related to the request
  timestamp: string;         // Query timestamp (ISO string)
  status: string;            // Status code (e.g., "evatr-0000")
  vatIdOwn: string;          // Normalized own VAT-ID used for API request
  vatIdForeign: string;      // Normalized foreign VAT-ID used for API request
  validFrom?: string;        // Valid from date (ISO string)
  validTill?: string;        // Valid until date (ISO string)
  company?: QualifiedResultCode;  // Company name validation result
  street?: QualifiedResultCode;   // Street validation result
  zip?: QualifiedResultCode;      // ZIP code validation result
  location?: QualifiedResultCode; // Location validation result
  raw?: string;                // Raw response from API (only if includeRaw is true)
}

The API uses German terms, which have been mapped to the following English parameters:

| BZSt API | evatr-api | |-----------------|---------------| | id | id | | anfrageZeitpunkt| timestamp | | status | status | | gueltigAb | validFrom | | gueltigBis | validTill | | ergFirmenname | company | | ergStrasse | street | | ergPlz | zip | | ergOrt | location |

Extended Response

By passing true as the second parameter to function validateSimple({...}, true) or validateQualified({...}, true) an ExtendedResponse object is returned. It maps date strings to Date objects, adds convenience fields valid and message, and provides a timestamp object with both the original string and a parsed Date:

interface ExtendedResponse {
  id: string;                      // Technical request ID returned by the API, related to the request
  timestamp: Timestamp;            // Timestamp object with original string and Date object
  valid: boolean;                  // true if isSuccessStatus()
  status: string;
  message?: string;                // German description for the status
  vatIdOwn: string;                // Normalized own VAT-ID used for API request
  vatIdForeign: string;            // Normalized foreign VAT-ID used for API request
  validFrom?: Date;                // Date object
  validTill?: Date;                // Date object
  company?: QualifiedResultCode;
  street?: QualifiedResultCode;
  zip?: QualifiedResultCode;
  location?: QualifiedResultCode;
  raw?: string;
}

Validation Results (Qualified Validation)

For qualified validation, the response includes validation results for each field:

  • A - Data matches registered information
  • B - Data does not match registered information
  • C - Data was not requested
  • D - Data not provided by the EU member state

Utility Functions

The library includes helpful utility functions via EvatrUtils:

import { EvatrUtils } from 'evatr-api';

// Validate VAT-ID format
EvatrUtils.checkVatIdSyntaxForCountry('DE123456789', 'DE'); // true

// Get country information
EvatrUtils.getCountryName('DE'); // 'Germany'
EvatrUtils.isEUMemberState('DE'); // true

// Check validation capability
EvatrUtils.canValidate('DE123456789', 'ATU12345678'); // true
EvatrUtils.canValidate('DE123456789', 'DE987654321'); // false (can't validate DE->DE)

// Get test VAT-IDs for development
const testIds = EvatrUtils.getTestVatIds();

Migration Helper (Backward Compatibility)

For users migrating from the evatr library, we provide a migration helper that maintains API compatibility.

[!IMPORTANT] The migration helper was introduced because the German Federal Central Tax Office is sunsetting the XML-RPC API on November 30th, 2025. This helper allows existing code to work with minimal changes while using the new REST API under the hood.

Why the Migration Helper?

The new REST API has several differences from the XML-RPC API:

  • JSON responses instead of XML
  • Different parameter names
  • Different response structure
  • Different error codes and messages
  • There is no standard yet on English naming conventions for request and response parameters in context of VAT-ID validation

Usage

import { EvatrMigrationHelper as evatr } from 'evatr-api';

// Simple validation (matches original evatr API)
const result = await evatr.checkSimple({
  ownVatNumber: 'DE123456789',
  validateVatNumber: 'ATU12345678'
});

// Qualified validation (matches original evatr API)
const qualifiedResult = await evatr.checkQualified({
  ownVatNumber: 'DE123456789',
  validateVatNumber: 'ATU12345678',
  companyName: 'Musterhaus GmbH & Co KG',
  street: 'Musterstrasse 22',
  zip: '12345',
  city: 'musterort',
});

Breaking Changes

While the migration helper tries to maintain API compatibility, there are some unavoidable breaking changes:

| Change | evatr | evatr-api | |--------|---------------|----------------------------------| | Raw data parameter | includeRawXml | includeRaw | | Raw data response | rawXml (XML string) | raw (JSON string) | | Error codes | XML-RPC specific codes | Mapped to legacy codes (best effort) | | Error descriptions | Based on error code | Based on REST API status messages | | Additional field | - | status (new REST API status code) |

[!NOTE] API status codes have been mapped to legacy codes to the best of our knowledge. If an API status does not correspond to a legacy code, the 999 legacy code is being returned. We recommend to relay on API status.

[!TIP] See the migration helper example for a complete usage demonstration.

Mapping

The following tables show the parameter naming mapping between evatr and evatr-api:

Request

| evatr | evatr-api | |-------------------------|------------------------------| | ownVatNumber | vatIdOwn | | validateVatNumber | vatIdForeign | | companyName | company | | city | location | | street | street | | zip | zip | | includeRaw | includeRaw |

Response

| evatr | evatr-api | |--------------------------------|-----------------------------------------| | raw (XML) | raw (JSON) | | date | timestamp {0, 10} (format YYYY-MM-DD) | | time | timestamp {11, 8} (format HH:MM:SS) | | errorCode | - (replaced by status) | | errorDescription | - (use getStatusMessage() or message in ExtendedResponse) | | - (exists in migration helper) | status | | ownVatNumber | vatIdOwn | | validatedVatNumber | vatIdForeign | | validFrom | validFrom | | validTill | validTill | | valid | valid | | resultName | company | | resultCity | location | | resultStreet | street | | resultZip | zip | | resultNameDescription | - (use explainQualifiedResultCode()) | | resultCityDescription | - (use explainQualifiedResultCode()) | | resultStreetDescription | - (use explainQualifiedResultCode()) | | resultZipDescription | - (use explainQualifiedResultCode()) |

Error Handling

The library throws EvatrApiError for API-related errors:

try {
  const result = await client.validateSimple({
    anfragendeUstid: 'DE123456789',
    angefragteUstid: 'INVALID'
  });
} catch (error) {
  if (error.name === 'EvatrApiError') {
    console.log('Status:', error.status);
    console.log('HTTP Code:', error.http);
    console.log('Field:', error.field);
    console.log('Message:', error.message);
  }
}

API Updates

The library includes utilities to check for API updates:

# Check for all updates
npm run update:api check

# Check only API documentation
npm run update:api api-docs

# Check only status messages
npm run update:api status-messages

Update Workflow

  1. Check for updates: Run npm run update:api check to see if there are new versions
  2. Inspect output: Status message changes are displayed with added, removed, and modified messages
  3. Compare differences: Compare current file with updated versions using for example diff, New files are saved with timestamps (e.g., statusmeldungen-2025-08-01.json)
  4. Update constants: Update the TypeScript constants file with new messages:
npm run update:api update-constants ./docs/statusmeldungen-2025-08-01.json

Rate Limits and Best Practices

  • The BZSt API has rate limits for qualified validation requests
  • Add delays between requests when validating multiple VAT-IDs
  • Cache results when possible to avoid unnecessary API calls (for example for 12 hours)
  • Handle errors gracefully and provide meaningful feedback to users

Testing

npm test

Dummy data

The library includes test VAT-IDs and information that can be used for testing. These are official test VAT-IDs provided by the API documentation:

const testRequest = {
  anfragendeUstid: 'DE123456789',
  angefragteUstid: 'ATU12345678',
};

const qualifiedTestRequest = {
  anfragendeUstid: 'DE123456789',
  angefragteUstid: 'ATU12345678',
  firmenname: 'Musterhaus GmbH & Co KG',
  strasse: 'Musterstrasse 22',
  plz: '12345',
  ort: 'musterort',
};

Changelog

Please see Release Notes for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

If you discover any security-related issues, please email [email protected] instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.