Calculate Tax Before Checkout
Use the Tax Quote API to show tax breakdowns before payment.
Bags calculates VAT, GST, and sales tax automatically using regional tax providers routed by customer country (EU VAT, UK VAT, India GST, US sales tax where nexus is active, and zero-tax elsewhere). Request a tax quote before creating a checkout session to show your customers a breakdown of subtotal, tax, and total.
How it works
- Customer enters their billing address
- You call the tax quote endpoint with the payment link ID and address
- Bags returns the tax breakdown (subtotal, tax amount, total) and a signed
quoteToken - You pass the
quoteTokenwhen creating the checkout session to lock in the tax amount
The quote token is cryptographically signed and ensures the tax amount cannot be tampered with between the quote and checkout steps.
Request a tax quote
const response = await fetch("https://www.getbags.app/api/tax/quote", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BAG_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
paymentLinkId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
customerAddress: {
address_line_1: "100 Main St",
address_city: "San Francisco",
address_province: "CA",
address_postal_code: "94105",
address_country: "US",
address_type: "billing",
},
}),
});
const { data: quote } = await response.json();
console.log(`Subtotal: $${(quote.subtotalCents / 100).toFixed(2)}`);
console.log(`Tax: $${(quote.taxCents / 100).toFixed(2)}`);
console.log(`Total: $${(quote.totalCents / 100).toFixed(2)}`);import os
import requests
API_KEY = os.environ["BAG_API_KEY"]
BASE_URL = "https://www.getbags.app"
response = requests.post(
f"{BASE_URL}/api/tax/quote",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
json={
"paymentLinkId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"customerAddress": {
"address_line_1": "100 Main St",
"address_city": "San Francisco",
"address_province": "CA",
"address_postal_code": "94105",
"address_country": "US",
"address_type": "billing",
},
},
)
data = response.json()["data"]
print(f"Subtotal: ${data['subtotalCents'] / 100:.2f}")
print(f"Tax: ${data['taxCents'] / 100:.2f}")
print(f"Total: ${data['totalCents'] / 100:.2f}")curl -X POST https://www.getbags.app/api/tax/quote \
-H "Authorization: Bearer $BAG_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"paymentLinkId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"customerAddress": {
"address_line_1": "100 Main St",
"address_city": "San Francisco",
"address_province": "CA",
"address_postal_code": "94105",
"address_country": "US",
"address_type": "billing"
}
}'Response
{
"status": "success",
"data": {
"subtotalCents": 2999,
"taxCents": 262,
"totalCents": 3261,
"calculationId": "calc_abc123",
"quoteToken": "eyJhbGciOiJIUzI1NiIs..."
}
}| Field | Type | Description |
|---|---|---|
subtotalCents | number | Product price in cents before tax |
taxCents | number | Calculated tax amount in cents |
totalCents | number | Total amount including tax in cents |
calculationId | string | Provider calculation reference (format varies by region) |
quoteToken | string | Signed token to pass to checkout session creation |
Using the quote in checkout
Pass the quoteToken and totals snapshot when creating a checkout session via POST /api/checkout/session:
const response = await fetch("https://www.getbags.app/api/checkout/session", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
linkId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
quoteToken: quote.quoteToken,
walletAddress: "0xCustomerWallet",
walletType: "evm",
network: "base",
customer: {
name: "Jane Doe",
email: "jane@example.com",
address: "100 Main St, San Francisco, CA 94105",
country: "US",
},
totalsSnapshot: {
subtotalCents: quote.subtotalCents,
taxCents: quote.taxCents,
totalCents: quote.totalCents,
calculationId: quote.calculationId,
},
}),
});Address fields
| Field | Type | Required | Description |
|---|---|---|---|
address_line_1 | string | Yes | Street address |
address_city | string | Yes | City |
address_province | string | Yes | State, province, or region code |
address_postal_code | string | Yes | ZIP or postal code |
address_country | string | Yes | ISO 3166-1 alpha-2 country code (e.g., US, DE, GB) |
address_type | string | Yes | Must be "billing" |
Tax calculation details
Bags routes quotes to the active provider for the customer's country:
| Region | Provider (v0) |
|---|---|
| EU | Hardcoded EU VAT rates (per active country gate) |
| GB | UK VAT |
| IN | India GST |
| US | US sales tax (per active nexus state; $0 when no nexus) |
| Other | Zero tax |
Tax is based on the customer's billing address and Bags' MoR registration. Coverage expands as new regions activate — do not assume every jurisdiction returns non-zero tax. See Tax Collection & Filing for remittance.