Classify transactions¶
This page covers the classification of ledger transactions: deciding whether a row is business, personal, or mixed, adding the category and tax fields a calculation needs, recording mixed-use shares, batch and rule-based classification, and the review queue that lists everything still waiting for a decision. Use it after transactions are in the active profile’s ledger - imported rows have dates and amounts, but they do not yet say how the tax calculation should treat them.
Classifying a transaction changes only the record on your computer. It sends nothing to Spain’s Tax Agency (AEAT).
Before you start¶
You need:
An active taxpayer profile. Every command below works on the active profile; if none is set, the command refuses. See Set up your taxpayer profile.
A master-key passphrase. The tool prompts for it the first time it opens your encrypted storage in a session.
A ledger with transactions in it. See Import and manage transactions to import a bank statement or add rows by hand.
The CLI help and error text render in Spanish, even though this guide is in English. When a step sends you to --help, expect Spanish option names.
Review the row first¶
Find the transaction id, then inspect the row before you classify it. The sequence imports the standard quarter and inspects the unclassified expense:
aeat app ledger list --filter classification=NOT_YET_PROCESSEDaeat app ledger list --filter classification=NOT_YET_PROCESSEDACCOUNTING LEDGER TRANSACTIONS id full_id date amount description IVA category review_status 71a5db2b 71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518 2026-02-10 1210 Cobro factura F-2026-001 servicios de consultoria pending e3eeac5e e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d 2026-02-11 605 Compra de material de oficina proveedor local pending
aeat --format json app ledger view e3eeac5eaeat --format json app ledger view e3eeac5e{ "active_profile": "docs-sequence-sandbox", "command": "ledger.view", "notices": [], "result": { "bucket_id": "<bucket-id>", "review_status": "pending", "transaction": { "amount": "605", "attachment_ids": [], "booked_date": "2026-02-11", "business_classification": "NOT_YET_PROCESSED", "business_pct": null, "category_id": null, "classification_confidence": null, "classification_reason": "", "classified_at": null, "classified_by": "auto", "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 de material de oficina proveedor local", "direction": "OUTGOING", "fx_rate": null, "invoice_id": null, "irpf_category": null, "iva_amount": null, "iva_category": null, "iva_rate": null, "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": null, "taxable_base": null, "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d", "usage_ratio_id": null, "value_date": "2026-02-11", "value_in_eur": null }, "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d" }, "schema_version": "2", "status": "success" }
Confirm the row is still unclassified before you decide.
Use the description, amount, counterparty, source document, and business context to decide how to classify the row.
Choose the classification¶
Use one of the ledger classification states that command help accepts:
BUSINESSfor a fully business-related transactionPERSONALfor a personal transaction that should not feed tax calculationsMIXEDfor a transaction that is partly business and partly personal
Use only these three values. Cadrumo sets the others automatically.
Pick a category for expenses¶
List the accepted category ids, then classify an expense row with one. Expense rows normally need a category id before a modelo can calculate from them:
aeat app ledger categoriesaeat app ledger categoriesRECOGNISED LEDGER SPENDING CATEGORIES category-id (pass this exact value) family cuotas_colegiales social_security cuotas_autonomos_ss social_security mutualidad_alternativa social_security arrendamiento_local premises ibi_local_afecto premises suministros_local_afecto premises suministros_home_office_luz home_office_suministros suministros_home_office_agua home_office_suministros suministros_home_office_gas home_office_suministros suministros_home_office_internet home_office_suministros telefonia_fija home_office_suministros amortizacion_vivienda_afecto home_office_ownership ibi_vivienda_afecto home_office_ownership comunidad_vivienda_afecto home_office_ownership arrendamiento_vivienda_afecto home_office_ownership telefonia_movil telecoms material_oficina office software_suscripcion office hardware_amortizable office mobiliario_amortizable office reparaciones_conservacion office publicidad_marketing office formacion_profesional office vehiculo_combustible vehicle vehiculo_mantenimiento vehicle vehiculo_seguro vehicle vehiculo_peaje vehicle vehiculo_parking vehicle manutencion_dietas_nacional meals manutencion_dietas_extranjero meals asesoria_fiscal professional_services asesoria_juridica professional_services asesoria_contable professional_services viajes_transporte travel viajes_alojamiento travel seguros_responsabilidad_civil insurance seguros_salud_autonomo insurance gastos_bancarios financial gastos_financieros financial suministros_cliente_directos direct_costs subcontratacion direct_costs tributos_fiscalmente_deducibles taxes Pass the bare id, e.g. --category-id cuotas_colegiales (not a family-prefixed or compound key). Deductible expenses only. Income (INCOMING) transactions are classified by direction and need no --category-id; `ledger check` and `ledger preflight` do not flag income as missing_category. IRPF CATEGORIES FOR --irpf-category irpf-category (pass this exact value) use actividad_economica professional activity withholding (received or paid net) arrendamiento_local net-paid rent expense withholding arrendamiento_vivienda_afecto net-paid rent expense withholding trabajo employment income (not for net-paid invoices) Net-paid rent example: --category-id arrendamiento_local --irpf-category arrendamiento_local. Net-paid professional service: --category-id asesoria_fiscal --irpf-category actividad_economica.
aeat app ledger classify e3eeac5e --classification BUSINESS --category-id \
material_oficinaaeat app ledger classify e3eeac5e --classification BUSINESS --category-id `
material_oficinaID e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d Date 2026-02-11 Amount 605 Description Compra de material de oficina proveedor local Review status reviewed
aeat --format json app ledger view e3eeac5eaeat --format json app ledger view e3eeac5e{ "active_profile": "docs-sequence-sandbox", "command": "ledger.view", "notices": [], "result": { "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 classify", "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 de material de oficina proveedor local", "direction": "OUTGOING", "fx_rate": null, "invoice_id": null, "irpf_category": null, "iva_amount": null, "iva_category": null, "iva_rate": null, "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": null, "taxable_base": null, "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d", "usage_ratio_id": null, "value_date": "2026-02-11", "value_in_eur": null }, "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d" }, "schema_version": "2", "status": "success" }
Confirm the expense is classified as business with a category.
For money you received (income), Cadrumo does not usually need a category. It calculates income totals automatically.
Use OUTGOING plus an expense category for supplier purchases and other
deductible expenses. Use INCOMING for issued invoices, client payments, or
services rendered to customers. If you also track invoice records separately,
use aeat app ledger invoice with --kind received for supplier invoices and
--kind issued for customer invoices.
Add tax fields when needed¶
If a row needs regulated tax fields, add only the fields that apply. The sequence classifies the expense with its taxable base, rate, and IVA amount:
aeat app ledger classify e3eeac5e --classification BUSINESS --category-id \
material_oficina --taxable-base 500.00 --iva-rate 0.21 --iva-amount 105.00aeat app ledger classify e3eeac5e --classification BUSINESS --category-id `
material_oficina --taxable-base 500.00 --iva-rate 0.21 --iva-amount 105.00ID e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d Date 2026-02-11 Amount 605 Description Compra de material de oficina proveedor local Review status reviewed
aeat --format json app ledger view e3eeac5eaeat --format json app ledger view e3eeac5e{ "active_profile": "docs-sequence-sandbox", "command": "ledger.view", "notices": [], "result": { "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 classify", "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 de material de oficina proveedor local", "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": null, "taxable_base": "500", "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d", "usage_ratio_id": null, "value_date": "2026-02-11", "value_in_eur": null }, "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d" }, "schema_version": "2", "status": "success" }
Confirm the taxable base and IVA fields were recorded on the row.
Common fields include taxable base, IVA rate, IVA amount, IVA category, IRPF
category, and counterparty EU member state for intracommunity IVA cases. Use
aeat app ledger classify --help for the exact current option list.
For ordinary domestic IVA, use the taxable base, rate, and amount shown by the
invoice. For example, a EUR 121.00 purchase with 21 percent IVA usually has
--taxable-base 100.00 --iva-rate 0.21 --iva-amount 21.00.
Most purchases at the standard 21% rate need no --iva-category. Add it only
for special cases: reduced rate (food, books), exempt supplies, purchases from
EU suppliers, or recargo de equivalencia. Run
aeat app ledger classify --help to see the accepted values.
Classify mixed-use transactions¶
A mixed-use transaction is one you use partly for business and partly personally, such as a phone bill, a car cost, or a home-office expense. Record the business share so the calculation counts only the deductible part. The split can come from three places, in rising order of grounding: a percentage on a single record, a saved default ratio for a whole category, or a ratio worked out from your registered facts (for example, the registered home-office area against the size of your home). All three keep only the part of a cost that genuinely belongs to the business.
A MIXED row needs a proportionality reference before a modelo can calculate
from it. The reference is a saved category ratio applied through
--usage-ratio-id. A bare --business-pct records a percentage but does not
make the row ready; preflight still reports missing_proportionality_reference
until the row carries --usage-ratio-id.
For one-row commands, --usage-ratio-id lives on the allocate verb (and on
add), not on classify. Its value is the spending-category id, and the same
category must already have a saved ratio. The sequence checks the eligible
categories, saves a ratio, and allocates the share on a row:
aeat app ledger ratios eligibleaeat app ledger ratios eligiblebucket <profile-id> count 15 amortizacion_vivienda_afecto usage_ratio_home_area default=- override=. arrendamiento_vivienda_afecto usage_ratio_home_area default=- override=. comunidad_vivienda_afecto usage_ratio_home_area default=- override=. ibi_vivienda_afecto usage_ratio_home_area default=- override=. suministros_home_office_agua usage_ratio_home_area default=- override=. suministros_home_office_gas usage_ratio_home_area default=- override=. suministros_home_office_internet usage_ratio_home_area default=- override=. suministros_home_office_luz usage_ratio_home_area default=- override=. telefonia_fija usage_ratio_home_area default=- override=. telefonia_movil usage_ratio_personal default=- override=. vehiculo_combustible usage_ratio_personal default=- override=. vehiculo_mantenimiento usage_ratio_personal default=- override=. vehiculo_parking usage_ratio_personal default=- override=. vehiculo_peaje usage_ratio_personal default=- override=. vehiculo_seguro usage_ratio_personal default=- override=.
aeat app ledger ratios set telefonia_movil 0.5aeat app ledger ratios set telefonia_movil 0.5bucket <profile-id> telefonia_movil 0.5
aeat app ledger allocate {transaction_id} --business-pct 0.5 --usage-ratio-id \
telefonia_movil --category-id telefonia_movilaeat app ledger allocate {transaction_id} --business-pct 0.5 --usage-ratio-id `
telefonia_movil --category-id telefonia_movilID 80f1bbebb9176b41674513c8a1c593f2ba8e6304d6fa0a9bfe104dd2f081a73e Date 2026-03-15 Amount 60.5 Description Factura movil Review status reviewed
aeat --format json app ledger view {transaction_id}aeat --format json app ledger view {transaction_id}{ "active_profile": "docs-sequence-sandbox", "command": "ledger.view", "notices": [], "result": { "bucket_id": "<bucket-id>", "review_status": "reviewed", "transaction": { "amount": "60.5", "attachment_ids": [], "booked_date": "2026-03-15", "business_classification": "MIXED", "business_pct": "0.5", "category_id": "telefonia_movil", "classification_confidence": "1", "classification_reason": "aeat app ledger allocate", "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-03-15", "description": "Factura movil", "direction": "OUTGOING", "fx_rate": null, "invoice_id": null, "irpf_category": null, "iva_amount": null, "iva_category": null, "iva_rate": null, "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": null, "transaction_id": "80f1bbebb9176b41674513c8a1c593f2ba8e6304d6fa0a9bfe104dd2f081a73e", "usage_ratio_id": "telefonia_movil", "value_date": null, "value_in_eur": null }, "transaction_id": "80f1bbebb9176b41674513c8a1c593f2ba8e6304d6fa0a9bfe104dd2f081a73e" }, "schema_version": "2", "status": "success" }
Confirm the mixed-use row carries the allocated business share.
A row’s --usage-ratio-id must name a ratio-eligible category (the ones
ratios eligible lists, such as telefonia_movil or a home-office suministros
category), and the same category is passed as --category-id. The
--business-pct value must match the saved ratio for that category. The
classification follows the share automatically: a 0.5 allocation becomes
MIXED, a 1 allocation becomes BUSINESS, and a 0 allocation becomes
PERSONAL.
List or check the saved ratios at any time. The sequence saves a ratio, lists the saved ratios, and validates them:
aeat app ledger ratios set telefonia_movil 0.5aeat app ledger ratios set telefonia_movil 0.5bucket <profile-id> telefonia_movil 0.5
aeat app ledger ratios listaeat app ledger ratios listbucket <profile-id> count 1 telefonia_movil 0.5
aeat --format json app ledger ratios validateaeat --format json app ledger ratios validate{ "active_profile": "docs-sequence-sandbox", "command": "ledger.ratios.validate", "notices": [], "result": { "bucket_id": "<bucket-id>", "eligible_count": 15, "findings": [], "missing_overrides": [], "overrides_count": 1, "profile_present": true }, "schema_version": "2", "status": "success" }
Confirm the saved ratios validate cleanly.
Remove a category ratio you no longer want with
aeat app ledger ratios unset <category-id>.
For home-office expenses, save a ratio for the relevant home-office category and allocate as above. Home-office ratios follow the manual or saved ratio workflow; keep the census facts in your profile correct first - see Maintain Modelo 036 census facts in your profile.
Classify many rows from CSV¶
For bulk review, classify --file reads a CSV with columns
transaction_id, classification, and optional classification facts such as
category_id, business_pct, usage_ratio_id, taxable-base and IVA columns,
iva_category, and irpf_category. Prepare a narrow CSV holding only the rows
you mean to change, one row per transaction:
transaction_id,classification,category_id,business_pct,usage_ratio_id
<business-expense-id>,BUSINESS,<category-id>,,
<mixed-expense-id>,MIXED,<category-id>,0.5,<category-id>
<private-row-id>,PERSONAL,,,
The sequence below imports the quarter, lists the rows still needing a decision, exports a review snapshot to work from, applies a prepared CSV, and confirms the result:
aeat app ledger list --filter period=1T --filter year=2026 --filter \
classification=NOT_YET_PROCESSEDaeat app ledger list --filter period=1T --filter year=2026 --filter `
classification=NOT_YET_PROCESSEDACCOUNTING LEDGER TRANSACTIONS id full_id date amount description IVA category review_status 71a5db2b 71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518 2026-02-10 1210 Cobro factura F-2026-001 servicios de consultoria pending e3eeac5e e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d 2026-02-11 605 Compra de material de oficina proveedor local pending
aeat app ledger export --output ./ledger-2026-q1.csv --year 2026 --period 1Taeat app ledger export --output ./ledger-2026-q1.csv --year 2026 --period 1TBucket <profile-id> Export ID 5f0ddcff2e977990b1b5fd3fc6e107cf9b3cb3b5f7ac82e87d072c77fed11cf4 Rows 2 SHA-256 0becceaa2ef5f6edba6a89f5fee123b09f1a044d477005dd381cecb52f66213d Output ledger-2026-q1.csv
aeat app ledger classify --file fixtures/classifications-2026-1t.csvaeat app ledger classify --file fixtures/classifications-2026-1t.csvbulk classify: 2 rows, 2 applied, 0 skipped, 0 failed
aeat --format json app ledger view e3eeac5eaeat --format json app ledger view e3eeac5e{ "active_profile": "docs-sequence-sandbox", "command": "ledger.view", "notices": [], "result": { "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 classify --file", "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 de material de oficina proveedor local", "direction": "OUTGOING", "fx_rate": null, "invoice_id": null, "irpf_category": null, "iva_amount": null, "iva_category": null, "iva_rate": null, "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": null, "taxable_base": null, "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d", "usage_ratio_id": null, "value_date": "2026-02-11", "value_in_eur": null }, "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d" }, "schema_version": "2", "status": "success" }
Confirm the CSV batch classified the quarter's rows.
Use the CSV path when filtered review shows many rows you can classify safely from their descriptions, counterparties, and source documents. Keep a copy of the file. It gives you a record of how you classified that period if you are later asked to justify your return. This path does not batch-update amounts, descriptions, IVA values, notes, attachments, or split/merge state; use the transaction workflow for those row-level edits.
Apply stored rules automatically¶
Rules automatically classify transactions whose description contains a word or phrase you specify. Matching ignores uppercase and lowercase differences. The sequence adds a rule, lists the rules, previews the effect, then applies it:
aeat app ledger rule add --description-pattern material --classification BUSINESS \
--category-id material_oficinaaeat app ledger rule add --description-pattern material --classification BUSINESS `
--category-id material_oficinarule_id 16719284a6b5e971... pattern material classification BUSINESS priority 100
aeat app ledger rule listaeat app ledger rule listpriority classification pattern rule_id 100 BUSINESS material 16719284a6b5e971...
aeat app ledger rule apply --dry-runaeat app ledger rule apply --dry-rundry-run: 0 transaction(s) would be classified
aeat --format json app ledger rule applyaeat --format json app ledger rule apply{ "active_profile": "docs-sequence-sandbox", "command": "ledger.rule.apply", "notices": [], "result": { "applied": [], "count": null, "dry_run": null, "matched": 0, "no_match": 0, "rules_evaluated": 1, "skipped_already_classified": 0, "transactions_scanned": 0, "would_match": null }, "schema_version": "2", "status": "success" }
Confirm the stored rule is registered and applies cleanly.
Run --dry-run first. Add --reaffirm only if you want the rule to overwrite
classifications you already set by hand.
Use an LLM suggestion¶
Cadrumo can use a configured language model to suggest how to classify each transaction. The suggestion is a starting point. You must confirm or correct it. It does not fill in tax amounts such as taxable base, IVA rate, or IRPF category.
Use Classify transactions with an LLM for the full provider, preview, apply, and override flow.
See everything that still needs a decision¶
The review queue is one profile-wide list of everything that still wants your attention before a filing: transactions without a classification, invoice records that are unmatched or disputed, and verification findings on modelo drafts. Each row names the exact command that resolves it, so the queue is a to-do list you can work through top to bottom. The queue is read-only; items clear when you fix the underlying record with the command the row names. The sequence imports the quarter, then reads the queue:
aeat --format json app review queueaeat --format json app review queue{ "active_profile": "docs-sequence-sandbox", "command": "review.queue", "notices": [], "result": { "operation": "review.queue", "rows": [ { "affected_object_id": "71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518", "blocking": false, "bucket_id": "<bucket-id>", "canonical_next_command": "aeat app ledger review 71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518", "current_owner_surface": "app ledger", "item_id": "71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518", "kind": "ledger_transaction", "legal_refs": [], "modelo": null, "period": "2026-02", "reason": "Transaction pending classification", "severity": "normal", "since": "2026-02-10T00:00:00+00:00", "source_kind": "ledger_transaction", "state": "pending", "summary": "Transaction pending classification" }, { "affected_object_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d", "blocking": false, "bucket_id": "<bucket-id>", "canonical_next_command": "aeat app ledger review e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d", "current_owner_surface": "app ledger", "item_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d", "kind": "ledger_transaction", "legal_refs": [], "modelo": null, "period": "2026-02", "reason": "Transaction pending classification", "severity": "normal", "since": "2026-02-11T00:00:00+00:00", "source_kind": "ledger_transaction", "state": "pending", "summary": "Transaction pending classification" } ] }, "schema_version": "2", "status": "success" }
Confirm the review queue lists the pending work.
Each row shows the item id, its kind, the affected record, the period, a
severity (critical, high, normal, or info), and a final column with
the command to run next. Narrow the list by kind, modelo, or state:
aeat app review queue --kind ledger_transactionaeat app review queue --kind ledger_transactionID Kind Source kind Object Period Severity Next 71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518 ledger_transaction ledger_transaction 71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518 2026-02 normal aeat app ledger review 71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518 e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d ledger_transaction ledger_transaction e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d 2026-02 normal aeat app ledger review e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d
aeat app review queue --kind modelo_finding --modelo 303aeat app review queue --kind modelo_finding --modelo 303ID Kind Source kind Object Period Severity Next No items pending review.
aeat --format json app review queue --state allaeat --format json app review queue --state all{ "active_profile": "docs-sequence-sandbox", "command": "review.queue", "notices": [], "result": { "operation": "review.queue", "rows": [ { "affected_object_id": "71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518", "blocking": false, "bucket_id": "<bucket-id>", "canonical_next_command": "aeat app ledger review 71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518", "current_owner_surface": "app ledger", "item_id": "71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518", "kind": "ledger_transaction", "legal_refs": [], "modelo": null, "period": "2026-02", "reason": "Transaction pending classification", "severity": "normal", "since": "2026-02-10T00:00:00+00:00", "source_kind": "ledger_transaction", "state": "all", "summary": "Transaction pending classification" }, { "affected_object_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d", "blocking": false, "bucket_id": "<bucket-id>", "canonical_next_command": "aeat app ledger review e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d", "current_owner_surface": "app ledger", "item_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d", "kind": "ledger_transaction", "legal_refs": [], "modelo": null, "period": "2026-02", "reason": "Transaction pending classification", "severity": "normal", "since": "2026-02-11T00:00:00+00:00", "source_kind": "ledger_transaction", "state": "all", "summary": "Transaction pending classification" } ] }, "schema_version": "2", "status": "success" }
Confirm the queue can be narrowed by kind.
Accepted --kind tokens are ledger_transaction, purchase_invoice_evidence,
payable_invoice, collectible_invoice, and modelo_finding. The default
state is pending. Inspect one item in full, including the suggested next
command, with aeat app review view <item-id>. Modelo findings are grounded
in registry rules; add --explain to show the legal references, or use the
global --format json flag (before the command) for a legal_refs field on
every row.
Transaction items clear when you classify the row (this page). Invoice items clear when you link or update the invoice - see Attach invoices and receipts. Modelo findings clear when you fix the reported values and verify again - see Verify a filing.
Confirm readiness¶
Run preflight after classification. The sequence imports and classifies the quarter, then runs preflight and reads the ledger status:
aeat app ledger preflight --year 2026 --period 1Taeat app ledger preflight --year 2026 --period 1Tbucket <profile-id> period 2026 1T checked 2 issues 0 ready true
aeat --format json app ledger status --year 2026 --period 1Taeat --format json app ledger status --year 2026 --period 1T{ "active_profile": "docs-sequence-sandbox", "command": "ledger.status", "notices": [], "result": { "active_count": 2, "archived_count": 0, "bucket_id": "<bucket-id>", "business_expense_total": "605", "business_income_total": "1210", "business_net_total": "605", "checked_transaction_count": 2, "pending_review_count": 0, "period": { "code": "1T", "filing_year": 2026 }, "readiness_issue_count": 0, "readiness_issues": [], "ready": true, "reviewed_count": 2, "skipped_count": 0, "split_count": 0, "stale_filings": [], "stashed_count": 0, "total_count": 2, "unconverted_currency_count": 0 }, "schema_version": "2", "status": "success" }
Confirm preflight reports the classified quarter's readiness.
Preflight names rows that still need category, taxable base, IVA amount, IVA rate, currency, or proportionality reference.
Correct a classification¶
Re-run classify on the same transaction id. A manual decision replaces the
previous classification. The sequence classifies a row as business, then
corrects it to personal:
aeat app ledger classify e3eeac5e --classification PERSONALaeat app ledger classify e3eeac5e --classification PERSONALID e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d Date 2026-02-11 Amount 605 Description Compra de material de oficina proveedor local Review status reviewed
aeat --format json app ledger view e3eeac5eaeat --format json app ledger view e3eeac5e{ "active_profile": "docs-sequence-sandbox", "command": "ledger.view", "notices": [], "result": { "bucket_id": "<bucket-id>", "review_status": "reviewed", "transaction": { "amount": "605", "attachment_ids": [], "booked_date": "2026-02-11", "business_classification": "PERSONAL", "business_pct": null, "category_id": null, "classification_confidence": "1", "classification_reason": "aeat app ledger classify", "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 de material de oficina proveedor local", "direction": "OUTGOING", "fx_rate": null, "invoice_id": null, "irpf_category": null, "iva_amount": null, "iva_category": null, "iva_rate": null, "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": null, "taxable_base": null, "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d", "usage_ratio_id": null, "value_date": "2026-02-11", "value_in_eur": null }, "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d" }, "schema_version": "2", "status": "success" }
Confirm the re-classification replaced the previous decision.
Inspect the row again with ledger view before calculating.