Taxes
Apply the right VAT and tax rates to the documents you issue
Give a product or invoice line a tax class, and Enlivy applies the rate that fits the customer's status and location. For companies based in 32 European countries, Enlivy keeps ready-made classes up to date.
Set up your taxesFree account, no card needed.
THE ENLIVY TAX ENGINE
Every line taxed by the rules you set
Give each product a tax class once, and Enlivy applies the matching rate on every invoice.
Taxes no longer mean just adding a percentage to an invoice. The customer's country, business status, VAT number, EU rules, reverse charge, and e-invoice requirements can completely change the treatment of the same sale.
A tax class names what you sell, such as books or digital services, and holds one rate per country or selling situation. When you invoice, Enlivy applies the rate that fits the buyer's country and tax status.
- Bring tax rates across from Stripe when you import subscriptions, deduplicated, with no re-entry
- Set each rate as inclusive or exclusive
- Preview which rate applies to any customer before you send, with Simulate Mapping
- Changes to the platform-managed tax catalog are logged
-
One class per product, the rate chosen per customer
Assign a tax class to a product, a proposal line, or an invoice line. Enlivy applies the rate that fits where the customer is based and who they are: a consumer or a business, VAT-registered in the EU or not.
-
Start from Enlivy's rates, or build your own
Based in the EU, the UK, Switzerland, Norway, Iceland, or Liechtenstein? Use ready-made classes whose rates Enlivy keeps up to date, or create your own per product category, with a rate per country.
-
Tax details for electronic invoices
Add VAT category and exemption reason codes where needed, so supported electronic invoice files include more than a number and a percentage.
-
Linked to Stripe
Tax rates imported from Stripe stay linked to the Stripe rate they came from.
Keep tax rules together
Configure rates, review which rule applies, and carry the tax details into supported electronic invoice files.
- Rate selection
Enlivy filters and ranks all rates in a class against the customer's country, region, business status, and VAT registration, and applies the highest-priority match. No manual picking.
- EU B2B reverse charge
Configure a 0% rate for eligible EU business sales, with the relevant category and exemption reason codes. Review the result before issuing an invoice.
- Catch-all safety net
A rate with no location covers any sale no country rate matches. Without one, that sale carries no tax, and Simulate Mapping warns you when the customer you describe would not be taxed.
- Tax applied at billing time
Tax is determined when each invoice is generated, not when the proposal was accepted. VAT changes mid-contract, and customer status changes, flow onto the next invoice automatically.
- Structured invoice details
Enlivy can include line-level VAT categories, a grouped VAT breakdown and party VAT numbers in supported electronic invoice exports.
- Inclusive & exclusive pricing
Mark a tax rate as inclusive and Enlivy extracts the VAT from the price. The customer pays the listed amount; the invoice breakdown is still complete and correct.
- Country, region & postal targeting
Location targeting works for any country down to region and postal code level. A single rate can cover multiple countries, or zero, to act as a global catch-all.
- Multilingual
Tax class names and descriptions can be saved in several languages, and the labels of EU VAT categories and exemption codes are translated too.
THE ENLIVY ADVANTAGE
Stop keeping tax rules in a spreadsheet. Use one system.
| Capability | Enlivy Taxes | Manual / spreadsheet approach |
|---|---|---|
| Rate selection | Automatic by country, business status, and VAT registration | Manual pick per invoice line, error-prone |
| EU B2B reverse charge | Configured once, applied automatically with the codes you set | Remembered per invoice, often missed or miscoded |
| VAT rate changes mid-contract | Enlivy applies the rate in force when it creates each invoice | Frozen at the rate when the contract was created |
| Electronic invoice tax details | VAT category and exemption reason codes where applicable | Details must be added to an electronic invoice separately |
| Inclusive pricing | Per-rate flag, Enlivy extracts VAT | Manual calculation each time, rounding errors accumulate |
| Multi-country coverage | One tax class holds a rate per country, plus a catch-all for the rest | Separate lookup or spreadsheet column per country |
| Stripe tax sync | Imported with your Stripe subscriptions, deduplicated, named with a Stripe prefix | Re-entered by hand, duplicates accumulate |
| Exempt invoices | An exempt rate requires its exemption reason code (VATEX), which goes onto the invoice | "Exempt" typed as text, rejected by e-invoicing platforms |
Set up your own tax class
Create a class and its rates when the ready-made classes do not fit what you sell.
-
Create a tax class
Click “Add Tax Class”. Give it a name (the one shown in dropdowns), an optional name to print on invoices, such as VAT or GST, and an optional description. You can then add its tax rates.
-
Add tax rates
Set the rate’s percentage, who it applies to and whether it depends on location. Give it a priority, so Enlivy knows which rate wins when more than one matches.
CHANGE RULES WITHOUT LOSING THE PAST
Retire a tax class with its connections in view
Before retiring a tax class you created, see everything that still uses it. Enlivy won't let you retire it while a product, an active billing schedule or billing package, an open proposal, or a draft invoice or receipt still uses it. Issued invoices and receipts keep the class they were issued with, and a retired class can no longer be chosen for anything new.
Tax across your Enlivy workspace
The same tax classes apply at every step of a sale, from the first proposal to the electronic invoice file.
- Products
Give each product a default tax class. When you add the product to an invoice or proposal line, its class comes with it.
- Proposals
A proposal line keeps the tax class, not a fixed rate. Enlivy applies the rate when the invoice is created, so a VAT change between the proposal and the invoice shows on the invoice.
- Billing Schedules
On a billing schedule, Enlivy applies the tax when it creates each invoice. Month 7 of a 12-month schedule uses the current rate, not the one from when the contract started.
- Invoices & Receipts
Tax is stored at two levels, per line item (full detail) and per invoice (grouped summary for Peppol). Both are automatically kept in sync.
- Stripe
When you import subscriptions from Stripe, the tax rates they use come across too, deduplicated and named with a Stripe prefix for easy identification.
- Network Exchanges
Tax details flow into the e-invoice files Enlivy creates in the EU standard.
API reference
Tax management from the API
Enlivy models tax the way Stripe models product tax codes, not one class per country. A tax class is a semantic product category (Standard goods & services, Books, Foodstuffs, Digital services, Exempt), and you tag each product with the category it is, never a percentage by hand. Each class holds its tax rates, one per country or selling situation. When you invoice, Enlivy applies the one rate that fits the buyer's country and tax status. If more than one fits, the rate with the highest priority wins.
The examples below cover both layers: the class (the category) and the rates (one per country or selling situation under each class).
List your product-tax categories. Include tax_rates_overview for a summary of the rate set resolving under each class.
/organizations/<organization_id>/tax-classes # filters: name, description, ids
# include tax_rates_overview for a per-class summary of the rate set
curl -G 'https://api.enlivy.com/organizations/<organization_id>/tax-classes' \
--data-urlencode 'page=1' \
--data-urlencode 'limit=20' \
--data-urlencode 'include=tax_rates_overview' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' const baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
// filters: name, description, ids
// include tax_rates_overview for a per-class summary of the rate set
const query = new URLSearchParams({
page: "1",
limit: "20",
include: "tax_rates_overview",
});
const result = await fetch(`${baseUrl}/organizations/${organizationId}/tax-classes?${query}` , {
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
},
}).then((response) => response.json());Create one class per product category you sell. A class is a category, not a country and not a single rate; the country rows live underneath it. Products then point their organization_tax_class_id at the category they belong to.
/organizations/<organization_id>/tax-classes # Create one class per product CATEGORY you sell (Standard goods & services, Books,
# Foodstuffs, Accommodation, Digital services / SaaS, Exempt). A class is a category,
# not a country and not a single rate; the country rows live underneath it.
curl -X POST 'https://api.enlivy.com/organizations/<organization_id>/tax-classes' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"name_lang_map": {
"en": "Books & publications",
"ro": "Cărți și publicații"
},
"description_lang_map": {
"en": "Reduced-rate category for books and periodicals."
}
}'const baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
// Create one class per product CATEGORY you sell (Standard goods & services, Books,
// Foodstuffs, Accommodation, Digital services / SaaS, Exempt). A class is a category,
// not a country and not a single rate; the country rows live underneath it.
const result = await fetch(`${baseUrl}/organizations/${organizationId}/tax-classes` , {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
"Content-Type": "application/json" ,
},
body: JSON.stringify({
// the category, not a rate: per-locale maps
name_lang_map: {
en: "Books & publications",
ro: "Cărți și publicații",
},
description_lang_map: { en: "Reduced-rate category for books and periodicals." },
}),
}).then((response) => response.json());Update a category's labels, or soft-delete it (restore later). Deleting a class removes the category its rate rows resolve under, so remove or reassign those rows first.
/organizations/<organization_id>/tax-classes/<tax_class_id> +1# Update a category's labels
curl -X PUT 'https://api.enlivy.com/organizations/<organization_id>/tax-classes/<tax_class_id>' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"name_lang_map": {
"en": "Books & publications (2026)"
}
}'
# soft delete; restore via POST /tax-classes/restore/{taxClassId}
curl -X DELETE 'https://api.enlivy.com/organizations/<organization_id>/tax-classes/<tax_class_id>' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' const baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
const taxClassId = "<tax_class_id>";
// Update a category's labels
const result1 = await fetch(`${baseUrl}/organizations/${organizationId}/tax-classes/${taxClassId}` , {
method: "PUT",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
"Content-Type": "application/json" ,
},
body: JSON.stringify({
name_lang_map: { en: "Books & publications (2026)" },
}),
}).then((response) => response.json());
// soft delete; restore via POST /tax-classes/restore/{taxClassId}
const result2 = await fetch(`${baseUrl}/organizations/${organizationId}/tax-classes/${taxClassId}` , {
method: "DELETE",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
},
}).then((response) => response.json());List the rate rows. Expand the parent class and the locations each row applies to. For a per-class summary, use the class's tax_rates_overview include instead.
/organizations/<organization_id>/tax-rates # includes: organization, organization_tax_class, locations
curl -G 'https://api.enlivy.com/organizations/<organization_id>/tax-rates' \
--data-urlencode 'page=1' \
--data-urlencode 'limit=50' \
--data-urlencode 'include=organization_tax_class,locations' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' const baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
// includes: organization, organization_tax_class, locations
const query = new URLSearchParams({
page: "1",
limit: "50",
include: "organization_tax_class,locations",
});
const result = await fetch(`${baseUrl}/organizations/${organizationId}/tax-rates?${query}` , {
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
},
}).then((response) => response.json());A tax rate is one row in a class's rate set, not a standalone tax. Each row declares a scope, an EN16931 VAT category, and a priority; at invoice time Enlivy takes the highest-priority matching row. The canonical set: home-country domestic, EU B2B reverse charge, per-country OSS, and a rest-of-world catch-all.
/organizations/<organization_id>/tax-rates +3# A tax rate is ONE ROW in a class's rate set, not a standalone tax. Each row declares a
# scope (locations and/or buyer conditions), an EN16931 VAT category (eu_vat_class), and a
# priority. At invoice time Enlivy takes the highest-priority row whose scope + buyer match.
# The canonical rate set for one category (home country = Romania): four archetypes.
#
# Home-country domestic: the default when selling within Romania
curl -X POST 'https://api.enlivy.com/organizations/<organization_id>/tax-rates' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"organization_tax_class_id": "<standard_goods_class_id>",
"has_eu_vat_properties": true,
"is_compound": false,
"is_inclusive": false,
"name": "RO Domestic 21%",
"rate": 21,
"priority": 1000,
"eu_vat_class": "S",
"has_locations": true,
"locations": [
{
"country_code": "RO"
}
]
}'
# EU B2B reverse charge: 0%, matches ONLY VAT-registered businesses in other EU states
curl -X POST 'https://api.enlivy.com/organizations/<organization_id>/tax-rates' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"organization_tax_class_id": "<standard_goods_class_id>",
"has_eu_vat_properties": true,
"is_compound": false,
"is_inclusive": false,
"name": "EU B2B Reverse Charge",
"rate": 0,
"priority": 900,
"eu_vat_class": "AE",
"vatex_code": "VATEX-EU-AE",
"is_business_entity": true,
"is_eu_vat_registered": true,
"has_locations": true,
"locations": [
{
"country_code": "DE"
},
{
"country_code": "FR"
}
]
}'
# Per-country EU domestic (B2C digital / OSS): charge the buyer's own country rate
curl -X POST 'https://api.enlivy.com/organizations/<organization_id>/tax-rates' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"organization_tax_class_id": "<standard_goods_class_id>",
"has_eu_vat_properties": true,
"is_compound": false,
"is_inclusive": false,
"name": "DE Domestic 19%",
"rate": 19,
"priority": 800,
"eu_vat_class": "S",
"has_locations": true,
"locations": [
{
"country_code": "DE"
}
]
}'
# Rest of world: outside scope, 0%, no locations = catch-all fallback
curl -X POST 'https://api.enlivy.com/organizations/<organization_id>/tax-rates' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"organization_tax_class_id": "<standard_goods_class_id>",
"has_eu_vat_properties": true,
"is_compound": false,
"is_inclusive": false,
"name": "Rest of World (Outside Scope)",
"rate": 0,
"priority": 100,
"eu_vat_class": "O",
"vatex_code": "VATEX-EU-O",
"has_locations": false
}'const baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
const headers = {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
"Content-Type": "application/json" ,
};
// A tax rate is ONE ROW in a class's rate set, not a standalone tax. Each row declares a
// scope (locations and/or buyer conditions), an EN16931 VAT category (eu_vat_class), and a
// priority. At invoice time Enlivy takes the highest-priority row whose scope + buyer match.
// The canonical rate set for one category (home country = Romania): four archetypes.
//
// Home-country domestic: the default when selling within Romania
const result1 = await fetch(`${baseUrl}/organizations/${organizationId}/tax-rates` , {
method: "POST",
headers,
body: JSON.stringify({
organization_tax_class_id: "<standard_goods_class_id>",
has_eu_vat_properties: true,
is_compound: false,
is_inclusive: false,
name: "RO Domestic 21%",
rate: 21,
priority: 1000,
// Standard-rated, stamped on the invoice line
eu_vat_class: "S",
has_locations: true,
locations: [{ country_code: "RO" }],
}),
}).then((response) => response.json());
// EU B2B reverse charge: 0%, matches ONLY VAT-registered businesses in other EU states
const result2 = await fetch(`${baseUrl}/organizations/${organizationId}/tax-rates` , {
method: "POST",
headers,
body: JSON.stringify({
organization_tax_class_id: "<standard_goods_class_id>",
has_eu_vat_properties: true,
is_compound: false,
is_inclusive: false,
name: "EU B2B Reverse Charge",
rate: 0,
priority: 900,
eu_vat_class: "AE",
// exemption reason (PEPPOL)
vatex_code: "VATEX-EU-AE",
// buyer-qualification gates
is_business_entity: true,
is_eu_vat_registered: true,
has_locations: true,
locations: [{ country_code: "DE" }, { country_code: "FR" }],
}),
}).then((response) => response.json());
// Per-country EU domestic (B2C digital / OSS): charge the buyer's own country rate
const result3 = await fetch(`${baseUrl}/organizations/${organizationId}/tax-rates` , {
method: "POST",
headers,
body: JSON.stringify({
organization_tax_class_id: "<standard_goods_class_id>",
has_eu_vat_properties: true,
is_compound: false,
is_inclusive: false,
name: "DE Domestic 19%",
rate: 19,
priority: 800,
eu_vat_class: "S",
has_locations: true,
locations: [{ country_code: "DE" }],
}),
}).then((response) => response.json());
// Rest of world: outside scope, 0%, no locations = catch-all fallback
const result4 = await fetch(`${baseUrl}/organizations/${organizationId}/tax-rates` , {
method: "POST",
headers,
body: JSON.stringify({
organization_tax_class_id: "<standard_goods_class_id>",
has_eu_vat_properties: true,
is_compound: false,
is_inclusive: false,
name: "Rest of World (Outside Scope)",
rate: 0,
priority: 100,
eu_vat_class: "O",
vatex_code: "VATEX-EU-O",
has_locations: false,
}),
}).then((response) => response.json());Adjust a single row: change its percentage, VAT category, scope, or priority in the resolution ladder. Send only the fields you are changing.
/organizations/<organization_id>/tax-rates/<tax_rate_id> # Adjust a single row: its percentage, VAT category, scope, or priority in the ladder.
# Send only the fields you are changing.
curl -X PUT 'https://api.enlivy.com/organizations/<organization_id>/tax-rates/<tax_rate_id>' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"rate": 20,
"display_name": "VAT 20%"
}'const baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
const taxRateId = "<tax_rate_id>";
// Adjust a single row: its percentage, VAT category, scope, or priority in the ladder.
// Send only the fields you are changing.
const result = await fetch(`${baseUrl}/organizations/${organizationId}/tax-rates/${taxRateId}` , {
method: "PUT",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
"Content-Type": "application/json" ,
},
body: JSON.stringify({
// e.g. the RO domestic rate changes
rate: 20,
display_name: "VAT 20%",
}),
}).then((response) => response.json());Soft-delete a single row from a class's set, for example to retire a country you no longer sell into. It can be restored later.
/organizations/<organization_id>/tax-rates/<tax_rate_id> # soft delete; restore via POST /tax-rates/restore/{taxRateId}
curl -X DELETE 'https://api.enlivy.com/organizations/<organization_id>/tax-rates/<tax_rate_id>' \
-H "Authorization: Bearer $ENLIVY_API_TOKEN" \
-H 'Accept: application/json' const baseUrl = "https://api.enlivy.com" ;
const token = process.env.ENLIVY_API_TOKEN;
const organizationId = "<organization_id>";
const taxRateId = "<tax_rate_id>";
// soft delete; restore via POST /tax-rates/restore/{taxRateId}
const result = await fetch(`${baseUrl}/organizations/${organizationId}/tax-rates/${taxRateId}` , {
method: "DELETE",
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/json" ,
},
}).then((response) => response.json());Works together with
- Invoices Issue an invoice and email it to your client. A card payment goes to your own Stripe account and the invoice is marked paid. A bank transfer you mark paid yourself.
- Document Intake Drop a supplier invoice or a receipt. With your own AI key, Enlivy fills in the form for you to check and save.
- Network Exchanges Network Exchanges turns each invoice you issue into an e-invoice in the EU standard (EN 16931), ready to download. Where Enlivy is connected to a national e-invoicing system, today Romania's, it also sends and receives them for you.
- Receipts Record money in and money out, keep the payment file with each receipt, and let Enlivy issue the receipt when you mark an invoice paid with one of the payment methods you set for automatic receipts.
- Payslips Your accountant works out the figures, and you record each amount in Enlivy on its own line, under your country's payroll code. Enlivy checks that the lines match the payslip's totals.
- Data Export Choose the period and the record types, and download one archive for your accountant, with a summary spreadsheet for each type if you want one. Free on every plan.
- MCP Connect Claude, ChatGPT, Cursor, or another MCP-compatible assistant to work with your invoices, contracts, and pipeline, within your own permissions.