Official Node.js SDK for the Ziptax API - Get accurate sales and use tax rates for any US address.
- âś… Full TypeScript support with comprehensive type definitions
- âś… Promise-based async/await API
- âś… Automatic retry logic with exponential backoff
- âś… Request/response logging
- âś… Comprehensive error handling
- âś… Support for both CommonJS and ES Modules
- âś… Zero runtime dependencies (except axios)
- âś… 80%+ test coverage
- âś… TaxCloud order management integration (optional)
npm install @ziptax/node-sdkimport { ZiptaxClient } from '@ziptax/node-sdk';
// Initialize the client with your API key
const client = new ZiptaxClient({
apiKey: 'your-api-key-here',
});
// Get sales tax rate by address
const result = await client.getSalesTaxByAddress({
address: '200 Spectrum Center Drive, Irvine, CA 92618',
});
console.log('Total Tax Rate:', result.taxSummaries?.[0]?.rate);
console.log('Base Rates:', result.baseRates);const client = new ZiptaxClient({
apiKey: 'your-api-key-here',
baseURL?: 'https://api.zip-tax.com', // Optional: Override base URL
timeout?: 30000, // Optional: Request timeout in ms
enableLogging?: false, // Optional: Enable request/response logging
retryOptions?: {
maxAttempts: 3,
initialDelay: 1000,
maxDelay: 10000,
backoffMultiplier: 2,
},
});const client = new ZiptaxClient({
apiKey: 'your-ziptax-api-key-here',
taxCloudConnectionId: '25eb9b97-5acb-492d-b720-c03e79cf715a', // Optional: TaxCloud Connection ID (UUID)
taxCloudAPIKey: 'your-taxcloud-api-key-here', // Optional: TaxCloud API Key
// ... other options
});Note: TaxCloud order management features are optional and only available when both taxCloudConnectionId and taxCloudAPIKey are provided during client initialization.
Returns sales and use tax rate details from an address input.
const result = await client.getSalesTaxByAddress({
address: '200 Spectrum Center Drive, Irvine, CA 92618',
taxabilityCode?: '12345', // Optional: Product/service taxability code
countryCode?: 'USA', // Optional: 'USA' or 'CAN' (default: 'USA')
historical?: '202401', // Optional: Historical date (YYYYMM format)
format?: 'json', // Optional: 'json' or 'xml' (default: 'json')
});Returns sales and use tax rate details from a geolocation input.
const result = await client.getSalesTaxByGeoLocation({
lat: '33.65253',
lng: '-117.74794',
countryCode?: 'USA', // Optional: 'USA' or 'CAN' (default: 'USA')
historical?: '202401', // Optional: Historical date (YYYYMM format)
format?: 'json', // Optional: 'json' or 'xml' (default: 'json')
});Returns sales and use tax rate details from a postal code input.
const result = await client.getRatesByPostalCode({
postalcode: '92694', // Required: 5-digit US postal code
format?: 'json', // Optional: 'json' or 'xml' (default: 'json')
});Returns account metrics and usage information.
const metrics = await client.getAccountMetrics();
console.log('Requests:', metrics.request_count, '/', metrics.request_limit);
console.log('Usage:', metrics.usage_percent.toFixed(2), '%');The SDK includes optional TaxCloud integration for order management operations. These features require TaxCloud credentials to be configured during client initialization.
Create orders from marketplace transactions, pre-existing systems, or bulk uploads.
const orderResponse = await client.createOrder({
orderId: 'my-order-1',
customerId: 'customer-453',
transactionDate: '2024-01-15T09:30:00Z',
completedDate: '2024-01-15T09:30:00Z',
origin: {
line1: '323 Washington Ave N',
city: 'Minneapolis',
state: 'MN',
zip: '55401-2427',
},
destination: {
line1: '323 Washington Ave N',
city: 'Minneapolis',
state: 'MN',
zip: '55401-2427',
},
lineItems: [
{
index: 0,
itemId: 'item-1',
price: 10.8,
quantity: 1.5,
tax: { amount: 1.31, rate: 0.0813 },
tic: 0,
},
],
currency: { currencyCode: 'USD' },
});Retrieve a specific order by its ID from TaxCloud.
const order = await client.getOrder('my-order-1');
console.log('Order ID:', order.orderId);
console.log('Customer:', order.customerId);
console.log('Total Tax:', order.lineItems.reduce((sum, item) => sum + item.tax.amount, 0));Update an existing order's completedDate in TaxCloud.
const updatedOrder = await client.updateOrder('my-order-1', {
completedDate: '2024-01-16T10:00:00Z',
});Create a refund against an order in TaxCloud. An order can only be refunded once, regardless of whether the order is partially or fully refunded.
// Partial refund (specific items)
const refunds = await client.refundOrder('my-order-1', {
items: [
{
itemId: 'item-1',
quantity: 1.0,
},
],
});
// Full refund (omit items or pass empty array)
const fullRefunds = await client.refundOrder('my-order-1');All methods return fully typed responses:
interface V60Response {
metadata: V60Metadata;
baseRates?: V60BaseRate[];
service: V60Service;
shipping: V60Shipping;
sourcingRules?: V60SourcingRules;
taxSummaries?: V60TaxSummary[];
addressDetail: V60AddressDetail;
}
interface V60PostalCodeResponse {
version: string;
rCode: number;
results: V60PostalCodeResult[];
addressDetail: V60PostalCodeAddressDetail;
}
interface V60AccountMetrics {
request_count: number;
request_limit: number;
usage_percent: number;
is_active: boolean;
message: string;
}interface OrderResponse {
orderId: string;
customerId: string;
connectionId: string;
transactionDate: string;
completedDate: string;
origin: TaxCloudAddressResponse;
destination: TaxCloudAddressResponse;
lineItems: CartItemWithTaxResponse[];
currency: CurrencyResponse;
channel: string | null;
deliveredBySeller: boolean;
excludeFromFiling: boolean;
exemption: Exemption;
}
interface RefundTransactionResponse {
connectionId: string;
createdDate: string;
items: CartItemRefundWithTaxResponse[];
returnedDate?: string;
}See the full type definitions for complete details.
Note: Most API responses use camelCase field names (e.g., baseRates, taxSummaries), but account metrics use snake_case (e.g., request_count, is_active).
The SDK provides specific error types for different failure scenarios:
import {
ZiptaxError,
ZiptaxAPIError,
ZiptaxAuthenticationError,
ZiptaxValidationError,
ZiptaxNetworkError,
ZiptaxRateLimitError,
} from '@ziptax/node-sdk';
try {
const result = await client.getSalesTaxByAddress({
address: '200 Spectrum Center Drive',
});
} catch (error) {
if (error instanceof ZiptaxAuthenticationError) {
console.error('Invalid API key');
} else if (error instanceof ZiptaxValidationError) {
console.error('Invalid request parameters:', error.message);
} else if (error instanceof ZiptaxRateLimitError) {
console.error('Rate limit exceeded. Retry after:', error.retryAfter);
} else if (error instanceof ZiptaxNetworkError) {
console.error('Network error:', error.message);
} else if (error instanceof ZiptaxAPIError) {
console.error('API error:', error.statusCode, error.message);
} else if (error instanceof ZiptaxError) {
console.error('ZipTax error:', error.message);
} else {
console.error('Unexpected error:', error);
}
}When using TaxCloud features, a ZiptaxConfigurationError will be thrown if the credentials are not configured:
import { ZiptaxConfigurationError } from '@ziptax/node-sdk';
try {
const order = await client.createOrder({
orderId: 'my-order-1',
// ... order details
});
} catch (error) {
if (error instanceof ZiptaxConfigurationError) {
console.error('Please provide taxCloudConnectionId and taxCloudAPIKey during client initialization');
} else {
// Handle other errors
console.error('Error creating order:', error);
}
}// Fetch tax rates for multiple addresses in parallel
const addresses = [
'200 Spectrum Center Drive, Irvine, CA 92618',
'1600 Amphitheatre Parkway, Mountain View, CA 94043',
];
const results = await Promise.all(
addresses.map((address) => client.getSalesTaxByAddress({ address }))
);// Create multiple orders concurrently
const orders = [
{
orderId: 'order-1',
customerId: 'customer-1',
// ... order details
},
{
orderId: 'order-2',
customerId: 'customer-2',
// ... order details
},
];
const createdOrders = await Promise.all(
orders.map((order) => client.createOrder(order))
);
console.log(`Created ${createdOrders.length} orders`);const client = new ZiptaxClient({
apiKey: 'your-api-key-here',
retryOptions: {
maxAttempts: 5,
initialDelay: 2000,
maxDelay: 30000,
backoffMultiplier: 2,
shouldRetry: (error, attempt) => {
// Custom retry logic
return attempt < 3 && error.name === 'ZiptaxNetworkError';
},
},
});const client = new ZiptaxClient({
apiKey: 'your-api-key-here',
enableLogging: true, // Logs all requests and responses
});See the examples directory for more usage examples:
- Basic Usage - ZipTax tax rate lookups
- Async Operations - Concurrent requests
- Error Handling - Error handling patterns
- TaxCloud Orders - TaxCloud order management
Basic examples require a valid ZipTax API key:
# Run basic usage example
ZIPTAX_API_KEY=your-api-key npm run example:basic
# Run async operations example
ZIPTAX_API_KEY=your-api-key npm run example:async
# Run error handling example
ZIPTAX_API_KEY=your-api-key npm run example:errorsTaxCloud example requires both ZipTax and TaxCloud credentials:
# Run TaxCloud order management example
ZIPTAX_API_KEY=your-api-key \
TAXCLOUD_CONNECTION_ID=your-connection-id \
TAXCLOUD_API_KEY=your-taxcloud-key \
npm run example:taxcloudOr export the environment variables first:
export ZIPTAX_API_KEY=your-api-key
export TAXCLOUD_CONNECTION_ID=your-connection-id
export TAXCLOUD_API_KEY=your-taxcloud-key
npm run example:taxcloud- Node.js >= 18.0.0
- npm or yarn
# Install dependencies
npm install
# Run tests
npm test
# Run tests with coverage
npm run test:coverage
# Run linting
npm run lint
# Format code
npm run format
# Type check
npm run type-check
# Build the package
npm run buildContributions are welcome! Please see CONTRIBUTING.md for details.
MIT License - see LICENSE file for details.
- Documentation: https://www.zip-tax.com/documentation
- Email: support@zip.tax
- Issues: GitHub Issues