---
title: "Retrieve the tax catalog"
method: GET
path: "/tax-catalog"
tags: ["Taxes"]
---

# Retrieve the tax catalog

`GET /tax-catalog`

## Request

- Base URL: `https://api.factuarea.com/v1`
- URL: `https://api.factuarea.com/v1/tax-catalog`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-API-Key`

Return the Spanish tax catalog in one document: IVA/IGIC/IPSI regimes and rates, operation regimes, exemption causes, IRPF withholding rates and legal VAT/surcharge pairs.
- No company data or custom taxes (see `GET /v1/companies/{company}/taxes`); withholding rates are POSITIVE.
- Labels in es/en/ca; cacheable via `ETag` (304 on `If-None-Match`).

## Headers

- `Factuarea-Version` string, date

## Response `200`

- object
  - `data` TaxCatalog, required: The Spanish tax catalog as a single document: indirect tax regimes with their legal rates and VeriFactu code, header-level operation regimes, exemption causes with their article and legal wording, system withholding rates, and the legal VAT/equivalence-surcharge pairs. It carries no data of the authenticated company, so two different companies receive byte-identical bodies for the same language, and it is not an entity: it has no `id` and no `object`.
    - `primary_language` 'es' | 'en' | 'ca', required: Language resolved from `Accept-Language` (`es`, `en` or `ca`; `es` when the header is absent or names no supported language). It declares the primary language of the document; it does not filter it — every entry always carries all three translations. It travels inside the body on purpose, which is why two languages yield different `ETag`s.
    - `indirect_tax_regimes` TaxCatalogIndirectRegime[], required: Indirect tax regimes (IVA, IGIC, IPSI) with their legal rates, standard rate, VeriFactu L1 code and the AEAT zones that determine each one.
      - `code` 'iva' | 'igic' | 'ipsi', required: Stable identifier of the regime.
      - `aeat_code` '01' | '02' | '03', required: Code of the AEAT L1 list used by VeriFactu: `01` for IVA, `02` for IPSI, `03` for IGIC. Send this value, not the `code`, when a VeriFactu field expects the L1 list.
      - `valid_rates` number[], required: Every legal rate of the regime, in percentage points. Any other rate is rejected when the invoice line is created.
      - `general_rate` number, float, required: Standard rate of the regime, the sensible default when the line has no explicit rate.
      - `aeat_zones` string[], required: AEAT territorial zones that determine this regime. A company whose zone is listed here charges this tax.
      - `label` TaxCatalogLocalizedText, required: A catalog text in the three languages the API supports. All three are always present: the negotiated `Accept-Language` picks the primary language of the document, it never filters the payload, so a client rendering a multilingual selector does not need three requests.
        - `es` string, required: Spanish wording.
        - `en` string, required: English wording.
        - `ca` string, required: Catalan wording.
    - `operation_regimes` TaxCatalogOperationRegime[], required: Header-level operation regimes with the legal wording each one requires and whether it forces a zero VAT amount.
      - `code` 'general' | 'intracomunitaria' | 'importacion_exportacion' | 'isp', required: Stable identifier of the operation regime.
      - `legal_mention` string, nullable, required: Legal wording (in Spanish) that the invoice must carry for this regime. `null` for `general`, the ordinary domestic transaction, which requires none.
      - `requires_zero_vat` boolean, required: `true` when the regime forces a zero VAT amount on every line of the document.
      - `label` TaxCatalogLocalizedText, required: A catalog text in the three languages the API supports. All three are always present: the negotiated `Accept-Language` picks the primary language of the document, it never filters the payload, so a client rendering a multilingual selector does not need three requests.
        - `es` string, required: Spanish wording.
        - `en` string, required: English wording.
        - `ca` string, required: Catalan wording.
      - `description` TaxCatalogLocalizedText, required: A catalog text in the three languages the API supports. All three are always present: the negotiated `Accept-Language` picks the primary language of the document, it never filters the payload, so a client rendering a multilingual selector does not need three requests.
        - `es` string, required: Spanish wording.
        - `en` string, required: English wording.
        - `ca` string, required: Catalan wording.
    - `exemption_causes` TaxCatalogExemptionCause[], required: Exemption, non-subjection and special-regime causes with their AEAT codes, legal wording, applicable article and whether they can be declared per line.
      - `code` string, required: Stable identifier of the cause.
      - `calificacion_operacion` 'S2' | 'N1' | 'N2' | 'null', nullable, required: Code of the AEAT L9 list (transaction qualification): `S2` for reverse charge, `N1`/`N2` for the two non-subjection cases. `null` when the cause is an exemption or a special regime.
      - `causa_exencion` 'E1' | 'E2' | 'E3' | 'E4' | 'E5' | 'E6' | 'null', nullable, required: Code of the AEAT L10 list (exemption reason), `E1` to `E6`. `null` when the cause is not an exemption.
      - `clave_regimen` '03' | '05' | '07' | '19' | '51' | 'null', nullable, required: Code of the AEAT L8A/L8B list (special regime key): `19` farming, `03` second-hand goods, `05` travel agencies, `51` equivalence surcharge, `07` cash accounting. `null` when no special regime applies.
      - `legal_mention` string, required: Full legal wording (in Spanish) that the invoice must carry when this cause is declared.
      - `article` string, nullable, required: Article of the Spanish VAT Act (Ley 37/1992) the cause relies on. `null` only for `otro`, whose wording is written by hand and has no determined article — `null` means "no article", never "not mapped".
      - `line_level` boolean, required: `true` when the cause can be declared per invoice line (its projected code is one of `E1`-`E6`, `N1`, `N2`). `false` for the special regimes, `otro` and reverse charge, which can only be declared in the document header.
      - `label` TaxCatalogLocalizedText, required: A catalog text in the three languages the API supports. All three are always present: the negotiated `Accept-Language` picks the primary language of the document, it never filters the payload, so a client rendering a multilingual selector does not need three requests.
        - `es` string, required: Spanish wording.
        - `en` string, required: English wording.
        - `ca` string, required: Catalan wording.
      - `description` TaxCatalogLocalizedText, required: A catalog text in the three languages the API supports. All three are always present: the negotiated `Accept-Language` picks the primary language of the document, it never filters the payload, so a client rendering a multilingual selector does not need three requests.
        - `es` string, required: Spanish wording.
        - `en` string, required: English wording.
        - `ca` string, required: Catalan wording.
    - `retention_rates` TaxCatalogRetentionRate[], required: System withholding rates, expressed in positive. Mostly IRPF withholdings, plus one contractual retainer that is not a tax and one IRNR rate (see the entry schema). The catalog of what the platform offers, not an exhaustive list of every rate Spanish law defines.
      - `code` string, required: Stable identifier of the withholding type. It is the key, not the `rate`: two different types can share the same percentage and `applies_to` and differ only in the case they cover.
      - `rate` number, float, required: Withholding percentage, always POSITIVE. Apply it as a deduction from the taxable base; the sign convention of the contract is positive regardless of how the rate is stored internally.
      - `applies_to` 'sale' | 'purchase', required: `sale` for withholdings you apply on your own invoices, `purchase` for withholdings a supplier applies on theirs.
      - `label` TaxCatalogLocalizedText, required: A catalog text in the three languages the API supports. All three are always present: the negotiated `Accept-Language` picks the primary language of the document, it never filters the payload, so a client rendering a multilingual selector does not need three requests.
        - `es` string, required: Spanish wording.
        - `en` string, required: English wording.
        - `ca` string, required: Catalan wording.
    - `equivalence_surcharge_pairs` TaxCatalogSurchargePair[], required: Closed matrix of the legal VAT/equivalence-surcharge pairs of article 161 of the Spanish VAT Act.
      - `vat` number, float, required: VAT rate of the pair, in percentage points.
      - `surcharge` number, float, required: Equivalence surcharge that legally accompanies that VAT rate.
      - `label` TaxCatalogLocalizedText, required: A catalog text in the three languages the API supports. All three are always present: the negotiated `Accept-Language` picks the primary language of the document, it never filters the payload, so a client rendering a multilingual selector does not need three requests.
        - `es` string, required: Spanish wording.
        - `en` string, required: English wording.
        - `ca` string, required: Catalan wording.

## Other responses

- `304`: The catalog has not changed since the validator you sent in `If-None-Match`. No body is returned; the cache headers of the 200 are repeated so the cached copy can be refreshed (RFC 9110 §15.4.5).
- `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`).
- `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)
