Skip to content

Tax Calculation

Tax Calculation

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

Endpoint

POST /v1/calculate

Request Body

FieldTypeRequiredDescription
line_itemsarrayYesArray of items in the transaction (1-100 items)
line_items[].amountintegerYesPrice in cents (e.g., 9999 = $99.99)
line_items[].product_typestringYesProduct category (see below)
line_items[].quantityintegerNoQuantity (default: 1)
line_items[].descriptionstringNoItem description
customer.address.countrystringYes2-letter ISO country code
customer.address.regionstringNoState/province code (required for US/CA)
customer.address.postal_codestringNoPostal/ZIP code
seller.registered_inarrayNoJurisdictions where seller collects tax
currencystringYes3-letter ISO currency code
transaction_datestringNoDate in YYYY-MM-DD format (default: today)

Product Types

TypeDescription
physical_goodsTangible products
digital_goodsDownloadable products (ebooks, software)
saasSoftware as a Service subscriptions
servicesProfessional services
streamingStreaming media services

Example 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": 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"
}'

Response

{
"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"
}

Response Fields

FieldTypeDescription
subtotalintegerSum of all line item amounts (cents)
tax_amountintegerTotal tax to collect (cents)
totalintegersubtotal + tax_amount (cents)
tax_ratenumberEffective tax rate as percentage
tax_breakdownarrayTax grouped by jurisdiction and type
line_itemsarrayPer-item tax calculation results
seller_registeredbooleanWhether seller is registered in destination
warningsarrayNon-fatal warnings about the calculation
queried_atstringISO timestamp of the calculation

Seller Registration

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.

Taxability Rules

Different product types have different tax rules per jurisdiction:

JurisdictionSaaSDigital GoodsPhysical Goods
EU countriesTaxable (VAT)Taxable (VAT)Taxable (VAT)
US-CAExemptExemptTaxable
US-TXTaxableTaxableTaxable
US-ORNo sales taxNo sales taxNo 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"
}
]
}

Multiple Line Items

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
}
]
}

US State Sales Tax

For US destinations, always include the region field:

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

Warnings

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 Responses

400 Bad Request

{
"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"]
}
}
}

404 Not Found

{
"error": "Jurisdiction not found",
"jurisdiction": "XX"
}

Integration Example

// 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)}`);