Skip to content

Tax Calculation

Calculate the tax for a transaction, including support for multiple line items, product-specific taxability rules, and seller registration validation.

POST /v1/calculate
Field Type Required Description
line_items array Yes Array of items in the transaction (1-100 items)
line_items[].amount integer Yes Price in cents (e.g., 9999 = $99.99)
line_items[].product_type string Yes Product category (see below)
line_items[].quantity integer No Quantity (default: 1)
line_items[].description string No Item description
customer.address.country string Yes 2-letter ISO country code
customer.address.region string No State/province code (required for US/CA)
customer.address.postal_code string No Postal/ZIP code
seller.registered_in array No Jurisdictions where seller collects tax
currency string Yes 3-letter ISO currency code
transaction_date string No Date in YYYY-MM-DD format (default: today)
Type Description
physical_goods Tangible products
digital_goods Downloadable products (ebooks, software)
saas Software as a Service subscriptions
services Professional services
streaming Streaming media services
Terminal window
curl -X POST "https://api.shipvat.com/v1/calculate" \
-H "Authorization: Bearer sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"line_items": [
{
"amount": 9999,
"product_type": "saas",
"quantity": 1,
"description": "Pro plan - monthly"
}
],
"customer": {
"address": {
"country": "DE",
"postal_code": "10115"
}
},
"seller": {
"registered_in": ["US", "DE", "GB"]
},
"currency": "USD"
}'
{
"subtotal": 9999,
"tax_amount": 1899,
"total": 11898,
"tax_rate": 19,
"tax_breakdown": [
{
"jurisdiction": "DE",
"jurisdiction_name": "Germany",
"tax_type": "VAT",
"rate": 19,
"taxable_amount": 9999,
"tax_amount": 1899
}
],
"line_items": [
{
"amount": 9999,
"product_type": "saas",
"quantity": 1,
"description": "Pro plan - monthly",
"taxable": true,
"tax_rate": 19,
"tax_amount": 1899
}
],
"seller_registered": true,
"warnings": [],
"queried_at": "2024-01-15T10:30:00.000Z"
}
Field Type Description
subtotal integer Sum of all line item amounts (cents)
tax_amount integer Total tax to collect (cents)
total integer subtotal + tax_amount (cents)
tax_rate number Effective tax rate as percentage
tax_breakdown array Tax grouped by jurisdiction and type
line_items array Per-item tax calculation results
seller_registered boolean Whether seller is registered in destination
warnings array Non-fatal warnings about the calculation
queried_at string ISO timestamp of the calculation

The seller.registered_in array determines whether tax should be calculated:

  • Registered: Tax is calculated based on destination rules
  • Not registered: Returns tax_amount: 0 with a warning
{
"seller": {
"registered_in": ["US", "DE", "GB"]
}
}

For US and Canada, you can specify:

  • Federal level: "US" or "CA" (covers all states/provinces)
  • State/province level: "US-CA", "US-TX", "CA-ON", etc.

Different product types have different tax rules per jurisdiction:

Jurisdiction SaaS Digital Goods Physical Goods
EU countries Taxable (VAT) Taxable (VAT) Taxable (VAT)
US-CA Exempt Exempt Taxable
US-TX Taxable Taxable Taxable
US-OR No sales tax No sales tax No sales tax

When a product is exempt, the response includes:

{
"line_items": [
{
"taxable": false,
"tax_rate": 0,
"tax_amount": 0,
"taxability_reason": "SaaS is exempt in California"
}
]
}

Calculate tax for multiple items in one request:

Terminal window
curl -X POST "https://api.shipvat.com/v1/calculate" \
-H "Authorization: Bearer sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"line_items": [
{"amount": 4999, "product_type": "saas", "quantity": 1},
{"amount": 1999, "product_type": "services", "quantity": 2}
],
"customer": {"address": {"country": "GB"}},
"seller": {"registered_in": ["GB"]},
"currency": "GBP"
}'

Response aggregates tax across all items:

{
"subtotal": 8997,
"tax_amount": 1799,
"total": 10796,
"tax_rate": 20,
"tax_breakdown": [
{
"jurisdiction": "GB",
"jurisdiction_name": "United Kingdom",
"tax_type": "VAT",
"rate": 20,
"taxable_amount": 8997,
"tax_amount": 1799
}
]
}

For US destinations, always include the region field:

{
"customer": {
"address": {
"country": "US",
"region": "CA",
"postal_code": "94102"
}
}
}

The API may return warnings for:

  • Seller not registered in destination jurisdiction
  • No specific taxability rule found (using standard rate)
  • No rate found for the specified category
{
"warnings": [
"Seller is not registered to collect tax in Germany. Registration may be required based on sales thresholds. Use /v1/decision/collect to check."
]
}
{
"error": "Invalid request body",
"details": {
"errors": {
"line_items": ["At least one line item is required"],
"customer.address.country": ["Country must be a 2-letter ISO code"]
}
}
}
{
"error": "Jurisdiction not found",
"jurisdiction": "XX"
}
// Calculate tax before checkout
const response = await fetch('https://api.shipvat.com/v1/calculate', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
line_items: cart.items.map(item => ({
amount: Math.round(item.price * 100), // Convert to cents
product_type: item.taxCategory,
quantity: item.quantity,
description: item.name
})),
customer: {
address: {
country: customer.country,
region: customer.state,
postal_code: customer.postalCode
}
},
seller: {
registered_in: ['US', 'DE', 'GB', 'CA']
},
currency: 'USD'
})
});
const tax = await response.json();
// Display to customer
console.log(`Subtotal: $${(tax.subtotal / 100).toFixed(2)}`);
console.log(`Tax: $${(tax.tax_amount / 100).toFixed(2)}`);
console.log(`Total: $${(tax.total / 100).toFixed(2)}`);