---
title: "Calculate a tax over a base amount"
method: POST
path: "/companies/{company}/taxes/calculate"
tags: ["Taxes"]
---

# Calculate a tax over a base amount

`POST /companies/{company}/taxes/calculate`

## Request

- Base URL: `https://api.factuarea.com/v1`
- URL: `https://api.factuarea.com/v1/companies/{company}/taxes/calculate`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-API-Key`

Apply the referenced tax to a base amount and return the breakdown: base, tax_rate, tax_amount, total_amount and the full tax object.

## Path parameters

- `company` string, uuid, required

## Headers

- `Factuarea-Version` string, date

## Request body

- CalculateTaxRequest: Calculate a tax on a base amount. Body: `base` (number) and `taxes_id`, the public identifier (UUID v7) of the tax, never the tax ID of a company. Returns `base`, `tax_rate`, `tax_amount`, `total_amount` and `tax`.
  - `base` number, required
  - `taxes_id` string, uuid, required: Identifier (UUID v7) of the tax to apply, from the Factuarea catalog plus your company's own taxes. A well-formed but non-existent value returns 404 `tax_not_found`.

## Response `200`

- object
  - `data` TaxCalculation, required: Result of applying a tax to a base amount. Returned by `POST /v1/companies/{company}/taxes/calculate`.
    - `base` string, required: Base amount the tax is applied to (EUR), as a 2-decimal string.
    - `tax_rate` number, required: Applied tax rate, e.g. `21` for 21% VAT.
    - `tax_amount` string, required: Tax amount (base × tax_rate / 100), as a 2-decimal string.
    - `total_amount` string, required: Resulting total amount (base + tax_amount), as a 2-decimal string.
    - `tax` Tax, required: A tax rate configuration. Catalog partially global (`is_system=true` for system taxes, without `company_id`) and partially custom per company.
      - `id` string, required
      - `object` 'tax', required
      - `name` string, required: Human-readable name of the tax (e.g. "IVA 21%").
      - `code` string, required: Short tax code (e.g. "IVA21").
      - `rate` number, float, required: Applied tax rate, e.g. `21` for 21% VAT.
      - `type` 'vat' | 'retention' | 'surcharge' | 'other', required: Tax category: `vat` (VAT), `retention` (IRPF withholding), `surcharge` (equivalence surcharge), `other`.
      - `applies_to` 'sales' | 'purchases' | 'both', required: Scope where it applies: `sales` (sales only), `purchases` (purchases only), `both` (both).
      - `country` string, nullable, required: ISO 3166-1 alpha-2 country code (e.g. `ES`).
      - `is_default` boolean, required: true if this is the default tax for its `type` (independent of the `default_for_documents` map).
      - `is_active` boolean, required: Indicates whether the tax is enabled for use on new documents.
      - `is_system` boolean, required: true if the tax is from the global system catalog (not editable, without `company_id`).
      - `ownership` 'global' | 'company', required: Who owns the tax: `global` (Factuarea catalog, read-only for companies) or `company` (a tax created by your company, which only your company sees and can edit or delete).
      - `description` string, nullable, required: Free-text description of the tax.
      - `default_for_documents` object, required: Map `DocumentType -> bool` indicating for which document types this tax is default. Replaces the 5 legacy booleans `is_default_invoice/quote/delivery_note/proforma/purchase_invoice`.
        - `invoice` boolean, required
        - `quote` boolean, required
        - `delivery_note` boolean, required
        - `proforma` boolean, required
        - `purchase_invoice` boolean, required
        - `recurring_invoice` boolean, required
      - `customer_visible_label` string, nullable, required: Tax label shown to the end customer on documents (PDF, public link, email).
      - `external_reference` 'S1' | 'S2' | 'S3' | 'E1' | 'E2' | 'E3' | 'E4' | 'E5' | 'E6' | 'N1' | 'N2' | 'null', nullable, required: AEAT-SII / VeriFactu key (closed catalog: S1..S3 subject, E1..E6 exempt, N1..N2 not subject).
      - `valid_from` string, date, nullable, required: Legal effective start date of the rate (BOE). Format `YYYY-MM-DD`.
      - `valid_until` string, date, nullable, required: Legal effective end date of the rate. Invariant: `valid_until >= valid_from` when both are non-null.
      - `reverse_charge` boolean, required: Reverse charge (Art. 84.Uno.2º LIVA). Default `false`.
      - `country_aeat_zone` 'peninsula' | 'canarias' | 'ceuta' | 'melilla' | 'null', nullable, required: AEAT tax zone: `peninsula` (including the Balearic Islands), `canarias` (IGIC), `ceuta` (IPSI) or `melilla` (IPSI).
      - `indirect_tax_regime` 'iva' | 'igic' | 'ipsi' | 'null', nullable, required: Indirect tax regime DERIVED from the AEAT zone, read-only: `iva` (Península), `igic` (Canarias), `ipsi` (Ceuta/Melilla). Only set for `type=vat`; `null` otherwise.
      - `linked_surcharge_taxes_id` string, nullable, required: Identity (UUID v7) of the linked equivalence-surcharge tax. Foreign key to the global `taxes` table (key suffix `_taxes_id` per the UUID policy). `null` when there is no link.
      - `metadata` Metadata, nullable, required: A free map of up to 50 key→value pairs for storing arbitrary structured data (values are strings up to 500 characters). Unlike `custom_fields` — an ordered list of typed `{field, value}` pairs with display semantics, present on the six document resources — `metadata` is an unordered map for opaque integration data; a document may carry both. The master resources (Client, Supplier) have no `custom_fields`, so their `metadata` doubles as the custom-fields store. **Reserved keys (read-only).** When the system auto-issues an invoice from a payment correlation (Stripe/GoCardless/MONEI), it writes `stripe_subscription_id`, `stripe_invoice_id`, `billing_reason`, `period_start` and `period_end` into that invoice metadata automatically. Do not set or overwrite them by hand — the platform owns them and a manual value may be replaced when the correlation runs.
      - `created_at` string, date-time, nullable, required
      - `updated_at` string, date-time, nullable, required

## Other responses

- `400`: `parameter_unknown` with `subcode` `retired_active_profile_header`: the retired `X-Active-Profile` header was sent; the company goes in the path. `parameter_invalid_format` on `Factuarea-Version`: the header is not a `YYYY-MM-DD` date. `unsupported_api_version`: the `Factuarea-Version` date is not a supported version.
- `401`: Missing or invalid API key.
- `403`: The request is authenticated but not allowed: the API key lacks the required scope (`insufficient_scope`), the plan does not include the public API or this feature (`addon_not_active`, `feature_not_available_in_plan`), or the module is not available with a test key (`module_not_available_in_sandbox`).
- `404`: The requested resource does not exist or belongs to another company. `profile_not_found`: the company in the path does not exist, is not in the API key scope or belongs to the other environment (live or test).
- `422`: Validation failed. The `error.param` field identifies which input is invalid.
- `429`: Rate limit exceeded. Retry after the duration in `Retry-After`.
- `500`: Unexpected server error.

---

[API](https://skmtc.dev/factuarea/apis/factuarea-public-api.md) · [All operations](https://skmtc.dev/factuarea/apis/factuarea-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/factuarea/apis/factuarea-public-api/revisions/718e77934422?raw)
