Apply IVA prorrata deductions

Use this guide when the taxpayer cannot deduct all input IVA. This happens when the activity mixes operations that grant the right to deduct with operations that do not (exempt operations without the right to deduct). Spanish IVA calls this prorrata. Record the taxpayer’s prorrata choice once and the tool applies it to Modelo 303 and Modelo 390 automatically.

Cadrumo does not submit anything to AEAT. The prorrata register is local, profile-scoped taxpayer state, not an AEAT filing surface.

The tool needs a master-key passphrase and prompts for it.

Requirement: a valid taxpayer profile. Create one with aeat config profile create <name> before you start. Set up your taxpayer profile walks through it.

Which prorrata applies

  • General prorrata (LIVA art. 104): one deduction percentage applies to every deductible input for the year. Use it when the taxpayer has no reason to separate inputs.

  • Especial prorrata (LIVA art. 103): each input deducts by its own use. Fully deductible inputs deduct in full, inputs used only for non-deducting operations deduct nothing, and shared (“common”) inputs deduct at the general percentage. Tag each input with its use.

Elect nothing and the tool keeps the whole-entity general treatment its own settlement already produces. Use this guide only when the taxpayer elects a percentage or splits the business into differentiated sectors.

Elect general prorrata

Elect the year’s general percentage:

1Elect the year's general deduction percentage.
aeat --format json app ledger prorrata elect-general --ejercicio 2026 --percentage 80 \
  --provenance inicio_actividad --reference propuesta-inicio-2026
aeat --format json app ledger prorrata elect-general --ejercicio 2026 --percentage 80 `
  --provenance inicio_actividad --reference propuesta-inicio-2026
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.prorrata.elect_general",
  "notices": [],
  "result": {
    "bucket_id": "<bucket-id>",
    "count": 1,
    "entry": {
      "authorisation_reference": "propuesta-inicio-2026",
      "definitive_percentage": null,
      "definitive_volume_con_derecho": null,
      "definitive_volume_sin_derecho": null,
      "ejercicio": 2026,
      "especial_transition": null,
      "interrupted": false,
      "provisional_percentage": "80",
      "provisional_provenance": "inicio_actividad",
      "regime": "general",
      "schema_version": "2",
      "sector_id": null,
      "source_observation_ref": null,
      "source_registry_snapshot_refs": []
    }
  },
  "schema_version": "2",
  "status": "success"
}

Confirm the general election is recorded on the profile.

  • --ejercicio is the filing year the election covers.

  • --percentage is the provisional deduction percentage, 0 to 100 (LIVA art. 104.Uno + 105.Uno).

  • --provenance and --reference name the document the percentage stands on: inicio_actividad for a start-of-activity proposal (LIVA art. 105.Tres) or aeat_autorizada for an AEAT-authorised percentage (LIVA art. 105.Dos). The tool refuses a typed-in percentage without both.

  • To carry the prior year’s definitive percentage (LIVA art. 105.Uno), run aeat app ledger prorrata seed --ejercicio <year> instead. It reads the percentage from the filed prior-year Modelo 303 settlement.

Elect especial prorrata and classify inputs

Elect especial for the year:

1Elect especial prorrata for the year.
aeat --format json app ledger prorrata elect-especial --ejercicio 2026 --percentage 80 \
  --provenance inicio_actividad --reference propuesta-inicio-2026
aeat --format json app ledger prorrata elect-especial --ejercicio 2026 --percentage 80 `
  --provenance inicio_actividad --reference propuesta-inicio-2026
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.prorrata.elect_especial",
  "notices": [],
  "result": {
    "bucket_id": "<bucket-id>",
    "count": 1,
    "entry": {
      "authorisation_reference": "propuesta-inicio-2026",
      "definitive_percentage": null,
      "definitive_volume_con_derecho": null,
      "definitive_volume_sin_derecho": null,
      "ejercicio": 2026,
      "especial_transition": null,
      "interrupted": false,
      "provisional_percentage": "80",
      "provisional_provenance": "inicio_actividad",
      "regime": "especial",
      "schema_version": "2",
      "sector_id": null,
      "source_observation_ref": null,
      "source_registry_snapshot_refs": []
    }
  },
  "schema_version": "2",
  "status": "success"
}

Confirm the especial election replaces the general one for the year.

Here --percentage is the common-use percentage, the rate applied to shared inputs (LIVA art. 106.Uno regla 3.ª / art. 104.Dos). The same --provenance and --reference options apply.

Then tag each input row with its use when you add it:

1Tag a shared input with its common use as you add it.
aeat --format json app ledger add --date 2026-02-11 --amount 605 --direction OUTGOING \
  --description compra --classification BUSINESS --category-id material_oficina \
  --taxable-base 500 --iva-rate 0.21 --iva-amount 105 --input-classification common \
  --idempotency-key prorrata-common-input
aeat --format json app ledger add --date 2026-02-11 --amount 605 --direction OUTGOING `
  --description compra --classification BUSINESS --category-id material_oficina `
  --taxable-base 500 --iva-rate 0.21 --iva-amount 105 --input-classification common `
  --idempotency-key prorrata-common-input
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.add",
  "notices": [
    {
      "action": null,
      "code": "ledger.add.input_classification_inert",
      "context": {
        "ejercicio": "2026",
        "input_classification": "common",
        "sector_id": ""
      },
      "message": "Input classification has no effect for ejercicio 2026: no special-prorrata election applies, so the input is deducted at the general percentage. Classification becomes operative only while a special-prorrata election applies.",
      "severity": "warning"
    }
  ],
  "result": {
    "bucket_event_ids": [
      "caeb65ecf05baa47a01e14e67564264feceb179baf2127ff75c9c63cade1a86b"
    ],
    "bucket_id": "<bucket-id>",
    "review_status": "reviewed",
    "transaction": {
      "amount": "605",
      "attachment_ids": [],
      "booked_date": "2026-02-11",
      "business_classification": "BUSINESS",
      "business_pct": null,
      "category_id": "material_oficina",
      "classification_confidence": "1",
      "classification_reason": "aeat app ledger add",
      "classified_at": "2026-04-01T09:00:00+00:00",
      "classified_by": "manual",
      "counterparty": "",
      "counterparty_country": null,
      "counterparty_identification_state": null,
      "created_at": "2026-04-01T09:00:00+00:00",
      "currency": "EUR",
      "date": "2026-02-11",
      "description": "compra",
      "direction": "OUTGOING",
      "fx_rate": null,
      "invoice_id": null,
      "irpf_category": null,
      "iva_amount": "105",
      "iva_category": null,
      "iva_rate": "0.21",
      "lifecycle_state": "ACTIVE",
      "m210_income_classification": null,
      "modified_at": "2026-04-01T09:00:00+00:00",
      "notes": "",
      "prorrata_reference": null,
      "purchase_invoice_evidence_id": null,
      "source_jurisdiction": "ES",
      "taxable_base": "500",
      "transaction_id": "dbdbdfd18bb421c017e1f8516129455f2780b9062f3c33f0c67acadfbfebca31",
      "usage_ratio_id": null,
      "value_date": null,
      "value_in_eur": null
    },
    "transaction_id": "dbdbdfd18bb421c017e1f8516129455f2780b9062f3c33f0c67acadfbfebca31"
  },
  "schema_version": "2",
  "status": "warning"
}

Confirm the tagged common input is recorded in the ledger.

--input-classification takes one value:

  • exclusively_deductible - the input serves only operations that grant the right to deduct; it deducts in full.

  • exclusively_non_deductible - the input serves only operations that do not; it deducts nothing.

  • common - the input is shared; it deducts at the common-use percentage.

Tag an input but elect no especial for that year and the tool warns the tag is inert: the input deducts under the general percentage. Elect especial to make the tag take effect.

Declare a differentiated sector

Declare a differentiated sector when part of the activity has its own deduction regime (LIVA arts. 9.1.c / 101):

1Declare a differentiated sector with its LIVA letra and activity code.
aeat --format json app ledger prorrata declare-sector --sector-id arrendamiento --letra \
  c --activity-code 6820
aeat --format json app ledger prorrata declare-sector --sector-id arrendamiento --letra `
  c --activity-code 6820
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.prorrata.declare_sector",
  "notices": [],
  "result": {
    "bucket_id": "<bucket-id>",
    "count": 1,
    "sector": {
      "letra": "c",
      "member_activity_codes": [
        "6820"
      ],
      "sector_id": "arrendamiento"
    }
  },
  "schema_version": "2",
  "status": "success"
}

Confirm the differentiated sector is registered.

  • --sector-id is a stable id the register entries and ledger rows reference.

  • --letra is the LIVA art. 9.1.c letra that makes the sector differentiated: a, b, c, or d.

  • --activity-code is a CNAE or IAE code grouped into the sector. Repeat it for each code; give at least one.

Scope an election to a sector with --sector, and tag a row’s sector with --sector on ledger add:

1Scope the especial election to the differentiated sector.
aeat --format json app ledger prorrata elect-especial --ejercicio 2026 --percentage 80 \
  --provenance inicio_actividad --reference propuesta-inicio-2026 --sector arrendamiento
aeat --format json app ledger prorrata elect-especial --ejercicio 2026 --percentage 80 `
  --provenance inicio_actividad --reference propuesta-inicio-2026 --sector arrendamiento
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.prorrata.elect_especial",
  "notices": [],
  "result": {
    "bucket_id": "<bucket-id>",
    "count": 1,
    "entry": {
      "authorisation_reference": "propuesta-inicio-2026",
      "definitive_percentage": null,
      "definitive_volume_con_derecho": null,
      "definitive_volume_sin_derecho": null,
      "ejercicio": 2026,
      "especial_transition": null,
      "interrupted": false,
      "provisional_percentage": "80",
      "provisional_provenance": "inicio_actividad",
      "regime": "especial",
      "schema_version": "2",
      "sector_id": "arrendamiento",
      "source_observation_ref": null,
      "source_registry_snapshot_refs": []
    }
  },
  "schema_version": "2",
  "status": "success"
}
2Tag a row's sector as you add it.
aeat --format json app ledger add --date 2026-02-11 --amount 605 --direction OUTGOING \
  --description compra --classification BUSINESS --category-id material_oficina \
  --taxable-base 500 --iva-rate 0.21 --iva-amount 105 --sector arrendamiento \
  --input-classification common --idempotency-key prorrata-sector-input
aeat --format json app ledger add --date 2026-02-11 --amount 605 --direction OUTGOING `
  --description compra --classification BUSINESS --category-id material_oficina `
  --taxable-base 500 --iva-rate 0.21 --iva-amount 105 --sector arrendamiento `
  --input-classification common --idempotency-key prorrata-sector-input
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.add",
  "notices": [
    {
      "action": null,
      "code": "ledger.add.sector_unmatched",
      "context": {
        "sector_id": "arrendamiento"
      },
      "message": "--sector 'arrendamiento' matches no declared differentiated sector (LIVA arts. 9.1.c / 101), so this input is deducted at the common-use percentage rather than the sector percentage. The sector must exist before it can own the input.",
      "severity": "warning"
    }
  ],
  "result": {
    "bucket_event_ids": [
      "67462ff662ec83321d22d1ffcea235d9241320bf43f5e10ec61a0162eb1883ca"
    ],
    "bucket_id": "<bucket-id>",
    "review_status": "reviewed",
    "transaction": {
      "amount": "605",
      "attachment_ids": [],
      "booked_date": "2026-02-11",
      "business_classification": "BUSINESS",
      "business_pct": null,
      "category_id": "material_oficina",
      "classification_confidence": "1",
      "classification_reason": "aeat app ledger add",
      "classified_at": "2026-04-01T09:00:00+00:00",
      "classified_by": "manual",
      "counterparty": "",
      "counterparty_country": null,
      "counterparty_identification_state": null,
      "created_at": "2026-04-01T09:00:00+00:00",
      "currency": "EUR",
      "date": "2026-02-11",
      "description": "compra",
      "direction": "OUTGOING",
      "fx_rate": null,
      "invoice_id": null,
      "irpf_category": null,
      "iva_amount": "105",
      "iva_category": null,
      "iva_rate": "0.21",
      "lifecycle_state": "ACTIVE",
      "m210_income_classification": null,
      "modified_at": "2026-04-01T09:00:00+00:00",
      "notes": "",
      "prorrata_reference": null,
      "purchase_invoice_evidence_id": null,
      "source_jurisdiction": "ES",
      "taxable_base": "500",
      "transaction_id": "61875c80c3fc4eae14b9b58d1b245b46ccb6b7c8a2ae28ec1b013f626aded2c9",
      "usage_ratio_id": null,
      "value_date": null,
      "value_in_eur": null
    },
    "transaction_id": "61875c80c3fc4eae14b9b58d1b245b46ccb6b7c8a2ae28ec1b013f626aded2c9"
  },
  "schema_version": "2",
  "status": "warning"
}

Confirm the sector-scoped input is recorded against the declared sector.

Tag a row with a sector you have not declared and the tool warns the tag is unmatched: the input deducts at the common-use percentage until you declare the sector. Declare the sector first, or fix the id.

Read the settlement advisories

When you calculate the year-end Modelo 303 for the 4T settlement, the tool may surface non-blocking advisories:

  • Especial may be mandatory - when the taxpayer computes under general prorrata and especial would deduct at least 10% less, the law (LIVA art. 103.Dos.2) makes especial mandatory. Classify every input of the year so the tool can run this check; until then it prompts you to classify.

  • Inert classification - an --input-classification tag set with no especial election for that year.

  • Unmatched sector - a --sector tag naming a sector not yet declared.

These are advisories, not refusals. Read them alongside the calculation inputs before you verify the filing.

Review the register

List every election and declared sector on the active profile:

1List every prorrata election and declared sector.
aeat --format json app ledger prorrata list
aeat --format json app ledger prorrata list
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.prorrata.list",
  "notices": [],
  "result": {
    "bucket_id": "<bucket-id>",
    "count": 1,
    "entries": [
      {
        "authorisation_reference": "propuesta-inicio-2026",
        "definitive_percentage": null,
        "definitive_volume_con_derecho": null,
        "definitive_volume_sin_derecho": null,
        "ejercicio": 2026,
        "especial_transition": null,
        "interrupted": false,
        "provisional_percentage": "80",
        "provisional_provenance": "inicio_actividad",
        "regime": "general",
        "schema_version": "2",
        "sector_id": null,
        "source_observation_ref": null,
        "source_registry_snapshot_refs": []
      }
    ],
    "sectors": [
      {
        "letra": "c",
        "member_activity_codes": [
          "6820"
        ],
        "sector_id": "arrendamiento"
      }
    ]
  },
  "schema_version": "2",
  "status": "success"
}

Confirm the register reads back the elections and declared sector.

Next steps