Import and manage transactions¶
This page covers the ledger’s transaction workflow: importing your bank statement, adding any missing transactions by hand, reviewing and correcting them, and checking readiness before a calculation. A line on a bank statement is just a date and an amount - the tax meaning is added later, in classification.
Your bank records are not added automatically. aeat imports only when you run an import command. Tax calculations use the transactions you have saved under the active profile.
Before you start¶
You need:
a working
aeatcommandan active taxpayer profile; 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 bank statement file or directory, unless you are adding transactions by hand
for AEAT census-derived home-office ratios, reviewed censo facts; see Link Modelo 036 census information
Confirm the active profile before you write transaction data:
aeat --format json config profile statusaeat --format json config profile status{ "active_profile": "docs-sequence-sandbox", "command": "config.profile.status", "notices": [], "result": { "active_profile": "docs-sequence-sandbox", "activity_present": true, "configured": true, "iva_regime": "GENERAL", "precondition_action": null, "profile_id": "<profile-id>", "profile_record_error": null, "profile_record_present": null, "registered_profile": null, "tax_id_present": true, "tax_residence_ccaa": "" }, "schema_version": "2", "status": "success" }
Confirm a profile is active before you write transaction data.
Statement file format¶
A bank CSV uses a semicolon (;) separator and comma decimals. The first
line is the column header; each later line is one movement:
Fecha operación;Fecha valor;Concepto;Importe;Saldo;Moneda
2026-02-10;2026-02-10;Venta cliente;1.210,00;1.210,00;EUR
2026-02-11;2026-02-11;Compra material;-605,00;605,00;EUR
The sign of Importe carries the direction: a positive amount is income, a
negative amount is an expense.
Preview an import¶
Run a dry run first. A dry run shows what aeat would import and saves no rows.
Then repeat the command without --dry-run to save the rows. The sequence
previews the standard quarter’s statement, imports it, and confirms one imported
row:
aeat app ledger import --file fixtures/movimientos-2026-1t.csv --provider csv --dry-runaeat app ledger import --file fixtures/movimientos-2026-1t.csv --provider csv --dry-runRows 2 Entries imported 2 Skipped 0 DRY RUN MODE Yes Notice Dry run: no rows were saved. The counts above are a preview of what a real import would add and skip. notice ledger.import.dry_run_preview Dry run: no rows were saved. The counts above are a preview of what a real import would add and skip.
aeat app ledger import --file fixtures/movimientos-2026-1t.csv --provider csvaeat app ledger import --file fixtures/movimientos-2026-1t.csv --provider csvRows 2 Entries imported 2 Skipped 0
aeat --format json app ledger view 71a5db2baeat --format json app ledger view 71a5db2b{ "active_profile": "docs-sequence-sandbox", "command": "ledger.view", "notices": [], "result": { "bucket_id": "<bucket-id>", "review_status": "pending", "transaction": { "amount": "1210", "attachment_ids": [], "booked_date": "2026-02-10", "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-10", "description": "Cobro factura F-2026-001 servicios de consultoria", "direction": "INCOMING", "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": "71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518", "usage_ratio_id": null, "value_date": "2026-02-10", "value_in_eur": null }, "transaction_id": "71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518" }, "schema_version": "2", "status": "success" }
Confirm the statement's rows were imported into the ledger.
--provider csv names the statement format. --provider auto asks aeat to
detect it. The recognized providers are auto, csv, ofx, qfx, xlsx,
excel, n26, pdf, and pdf-n26. If detection picks the wrong format,
replace auto with the exact provider - run aeat app ledger import --help or
see the CLI reference for the current provider list.
If the path does not exist, the command refuses cleanly and names the missing
file (El archivo de origen no existe: ...); fix the path and run it again.
Save imported rows with diagnostics¶
Add --verify when you want import diagnostics alongside the save:
aeat app ledger import --file fixtures/movimientos-2026-1t.csv --provider csv --verifyaeat app ledger import --file fixtures/movimientos-2026-1t.csv --provider csv --verifyRows 2 Entries imported 2 Skipped 0 Valid Yes Detected format delimiter=';',quotechar='"' Source -
aeat --format json app ledger view 71a5db2baeat --format json app ledger view 71a5db2b{ "active_profile": "docs-sequence-sandbox", "command": "ledger.view", "notices": [], "result": { "bucket_id": "<bucket-id>", "review_status": "pending", "transaction": { "amount": "1210", "attachment_ids": [], "booked_date": "2026-02-10", "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-10", "description": "Cobro factura F-2026-001 servicios de consultoria", "direction": "INCOMING", "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": "71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518", "usage_ratio_id": null, "value_date": "2026-02-10", "value_in_eur": null }, "transaction_id": "71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518" }, "schema_version": "2", "status": "success" }
Confirm the verified import saved the statement's rows.
If the diagnostic source should point at a different original file, pass it with
--file <original>. Use --period only when you intentionally want to label the
import with a fiscal period; leave it out and aeat assigns the period from each
transaction’s date automatically.
Add one transaction manually¶
Use ledger add when a transaction is missing from imported statements.
Required fields are date, amount, direction, and description. Write the amount
as a positive figure - the direction carries whether money came in or went out,
and the command refuses a negative amount. OUTGOING is for expenses;
INCOMING is for income:
aeat --format json app ledger add --date 2026-03-15 --amount 49.99 --direction OUTGOING \
--description Software subscription --idempotency-key import-add-softwareaeat --format json app ledger add --date 2026-03-15 --amount 49.99 --direction OUTGOING `
--description Software subscription --idempotency-key import-add-software{ "active_profile": "docs-sequence-sandbox", "command": "ledger.add", "notices": [], "result": { "bucket_event_ids": [ "dfc77364ad10b11146bbcb8a7f77093f32da233a72a1a1346ea3bed72574a969" ], "bucket_id": "<bucket-id>", "review_status": "pending", "transaction": { "amount": "49.99", "attachment_ids": [], "booked_date": "2026-03-15", "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-03-15", "description": "Software subscription", "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": "bbdc3ab706b04e3f0afcc53616b99d697a76b4c8678f1e2817dcbe675913a1d5", "usage_ratio_id": null, "value_date": null, "value_in_eur": null }, "transaction_id": "bbdc3ab706b04e3f0afcc53616b99d697a76b4c8678f1e2817dcbe675913a1d5" }, "schema_version": "2", "status": "success" }
aeat --format json app ledger add --date 2026-03-20 --amount 121.00 --direction INCOMING \
--description Client payment --idempotency-key import-add-clientaeat --format json app ledger add --date 2026-03-20 --amount 121.00 --direction INCOMING `
--description Client payment --idempotency-key import-add-client{ "active_profile": "docs-sequence-sandbox", "command": "ledger.add", "notices": [], "result": { "bucket_event_ids": [ "d64492dc5b6c14fb7732d7831f25ae499f8df403d5e57aafd8e563a7e4c59329" ], "bucket_id": "<bucket-id>", "review_status": "pending", "transaction": { "amount": "121", "attachment_ids": [], "booked_date": "2026-03-20", "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-03-20", "description": "Client payment", "direction": "INCOMING", "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": "2314a0fb896fe26934f274d57ced8417a0881f7e3f286b34f8c300efd1a6e6d8", "usage_ratio_id": null, "value_date": null, "value_in_eur": null }, "transaction_id": "2314a0fb896fe26934f274d57ced8417a0881f7e3f286b34f8c300efd1a6e6d8" }, "schema_version": "2", "status": "success" }
aeat --format json app ledger add --date 2026-03-21 --amount 60.50 --direction OUTGOING \
--description Office supplies --idempotency-key import-add-suppliesaeat --format json app ledger add --date 2026-03-21 --amount 60.50 --direction OUTGOING `
--description Office supplies --idempotency-key import-add-supplies{ "active_profile": "docs-sequence-sandbox", "command": "ledger.add", "notices": [], "result": { "bucket_event_ids": [ "e1f4ade8214c0c3b747d99a79d73aa5735f6375e39115c473dc64093bbf30585" ], "bucket_id": "<bucket-id>", "review_status": "pending", "transaction": { "amount": "60.5", "attachment_ids": [], "booked_date": "2026-03-21", "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-03-21", "description": "Office supplies", "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": "8e9e36e8f65629149767b0a95c06a08c79cd61e03c3586aa66273419ec9ca43d", "usage_ratio_id": null, "value_date": null, "value_in_eur": null }, "transaction_id": "8e9e36e8f65629149767b0a95c06a08c79cd61e03c3586aa66273419ec9ca43d" }, "schema_version": "2", "status": "success" }
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": "pending", "transaction": { "amount": "49.99", "attachment_ids": [], "booked_date": "2026-03-15", "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-03-15", "description": "Software subscription", "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": "bbdc3ab706b04e3f0afcc53616b99d697a76b4c8678f1e2817dcbe675913a1d5", "usage_ratio_id": null, "value_date": null, "value_in_eur": null }, "transaction_id": "bbdc3ab706b04e3f0afcc53616b99d697a76b4c8678f1e2817dcbe675913a1d5" }, "schema_version": "2", "status": "success" }
Confirm a manually added transaction is stored with its direction.
The third direction, INTERNAL_TRANSFER, records money moved between your own
accounts.
Record tax details on a manual transaction¶
ledger add accepts the same tax fields you set during classification, so you
record a complete transaction in one step. --amount is the gross total
(taxable base plus IVA), and the tool refuses the row if the base plus IVA does
not match the gross to the cent:
aeat --format json app ledger add --date 2026-03-21 --amount 121.00 --direction OUTGOING \
--description Office supplies --counterparty Papeleria SL --category-id \
material_oficina --taxable-base 100.00 --iva-rate 0.21 --iva-amount 21.00 --notes \
Receipt filed --idempotency-key import-tax-detailsaeat --format json app ledger add --date 2026-03-21 --amount 121.00 --direction OUTGOING `
--description Office supplies --counterparty Papeleria SL --category-id `
material_oficina --taxable-base 100.00 --iva-rate 0.21 --iva-amount 21.00 --notes `
Receipt filed --idempotency-key import-tax-details{ "active_profile": "docs-sequence-sandbox", "command": "ledger.add", "notices": [], "result": { "bucket_event_ids": [ "2db62f858773cb6a333db409b8321094557fa580bd514110e48d1214f0f437b5" ], "bucket_id": "<bucket-id>", "review_status": "pending", "transaction": { "amount": "121", "attachment_ids": [], "booked_date": "2026-03-21", "business_classification": "NOT_YET_PROCESSED", "business_pct": null, "category_id": "material_oficina", "classification_confidence": null, "classification_reason": "", "classified_at": null, "classified_by": "auto", "counterparty": "Papeleria SL", "counterparty_country": null, "counterparty_identification_state": null, "created_at": "2026-04-01T09:00:00+00:00", "currency": "EUR", "date": "2026-03-21", "description": "Office supplies", "direction": "OUTGOING", "fx_rate": null, "invoice_id": null, "irpf_category": null, "iva_amount": "21", "iva_category": null, "iva_rate": "0.21", "lifecycle_state": "ACTIVE", "m210_income_classification": null, "modified_at": "2026-04-01T09:00:00+00:00", "notes": "Receipt filed", "prorrata_reference": null, "purchase_invoice_evidence_id": null, "source_jurisdiction": "ES", "taxable_base": "100", "transaction_id": "aebcbdf126dab613bfff9204b98d9bdce07dd43b900d9b0e1c00e24c709a2618", "usage_ratio_id": null, "value_date": null, "value_in_eur": null }, "transaction_id": "aebcbdf126dab613bfff9204b98d9bdce07dd43b900d9b0e1c00e24c709a2618" }, "schema_version": "2", "status": "success" }
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": "pending", "transaction": { "amount": "121", "attachment_ids": [], "booked_date": "2026-03-21", "business_classification": "NOT_YET_PROCESSED", "business_pct": null, "category_id": "material_oficina", "classification_confidence": null, "classification_reason": "", "classified_at": null, "classified_by": "auto", "counterparty": "Papeleria SL", "counterparty_country": null, "counterparty_identification_state": null, "created_at": "2026-04-01T09:00:00+00:00", "currency": "EUR", "date": "2026-03-21", "description": "Office supplies", "direction": "OUTGOING", "fx_rate": null, "invoice_id": null, "irpf_category": null, "iva_amount": "21", "iva_category": null, "iva_rate": "0.21", "lifecycle_state": "ACTIVE", "m210_income_classification": null, "modified_at": "2026-04-01T09:00:00+00:00", "notes": "Receipt filed", "prorrata_reference": null, "purchase_invoice_evidence_id": null, "source_jurisdiction": "ES", "taxable_base": "100", "transaction_id": "aebcbdf126dab613bfff9204b98d9bdce07dd43b900d9b0e1c00e24c709a2618", "usage_ratio_id": null, "value_date": null, "value_in_eur": null }, "transaction_id": "aebcbdf126dab613bfff9204b98d9bdce07dd43b900d9b0e1c00e24c709a2618" }, "schema_version": "2", "status": "success" }
Confirm the tax fields were recorded on the manual transaction.
Useful optional fields:
--currencyrecords a non-euro amount; it defaults toEUR.--counterpartyrecords who you paid or were paid by.--category-idassigns the income or expense category. Runaeat app ledger categoriesto list the ids.--taxable-base,--iva-rate, and--iva-amountrecord the IVA breakdown.--irpf-categoryrecords the IRPF (personal income tax) category.--source-jurisdictionrecords the country a movement belongs to, as an ISO two-letter code, which matters for non-resident scopes.--notesadds a short operator note.
For a part-business, part-personal movement, set --classification MIXED and the
business share with --business-pct, a value from 0 to 1. For the IVA
category, EU member-state, and usage-ratio semantics behind these fields, see
Classify transactions.
Use the invoice commands when you also need to track whether an invoice exists separately from the bank movement. Received invoices are supplier invoices you owe; issued invoices are customer invoices owed to you:
aeat --format json app ledger invoice add --kind received --counterparty-nif B12345674 \
--counterparty-name Proveedor SL --country-code ES --invoice-number 2026-0142 \
--invoice-date 2026-03-21 --taxable-base 100.00 --iva-rate 21aeat --format json app ledger invoice add --kind received --counterparty-nif B12345674 `
--counterparty-name Proveedor SL --country-code ES --invoice-number 2026-0142 `
--invoice-date 2026-03-21 --taxable-base 100.00 --iva-rate 21{ "active_profile": "docs-sequence-sandbox", "command": "ledger.invoice.add", "notices": [], "result": { "base_total": "100.00", "base_total_eur": "100.00", "bucket_id": "<bucket-id>", "counterparty_country": "ES", "counterparty_name": "Proveedor SL", "counterparty_tax_id": "sha256:133cad41", "currency": "EUR", "fx_rate": null, "fx_rate_date": null, "fx_rate_source": null, "grand_total": "121.00", "grand_total_eur": "121.00", "invoice_id": "58b9b176555a62584c1afd469cb548df417ab2531cacdbfb4673af2c98a0d6dd", "invoice_number": "2026-0142", "issued_at": "2026-03-21", "iva_total": "21.00", "iva_total_eur": "21.00", "kind": "received", "linked_transaction_ids": [], "notes": "", "operation_type": null, "payment_status": "PENDING", "recargo_amount": null, "retention_amount": null, "retention_rate": null }, "schema_version": "2", "status": "success" }
aeat app ledger invoice list --kind issuedaeat app ledger invoice list --kind issuedbucket <profile-id> count 0
aeat --format json app ledger invoice view {invoice_id}aeat --format json app ledger invoice view {invoice_id}{ "active_profile": "docs-sequence-sandbox", "command": "ledger.invoice.view", "notices": [], "result": { "base_total": "100.00", "base_total_eur": "100.00", "bucket_id": "<bucket-id>", "counterparty_country": "ES", "counterparty_name": "Proveedor SL", "counterparty_tax_id": "sha256:133cad41", "currency": "EUR", "fx_rate": null, "fx_rate_date": null, "fx_rate_source": null, "grand_total": "121.00", "grand_total_eur": "121.00", "invoice_id": "58b9b176555a62584c1afd469cb548df417ab2531cacdbfb4673af2c98a0d6dd", "invoice_number": "2026-0142", "issued_at": "2026-03-21", "iva_total": "21.00", "iva_total_eur": "21.00", "kind": "received", "linked_transaction_ids": [], "notes": "", "operation_type": null, "payment_status": "PENDING", "recargo_amount": null, "retention_amount": null, "retention_rate": null }, "schema_version": "2", "status": "success" }
Confirm the recorded invoice resolved to a payable invoice.
For the full invoice-record workflow, see Attach invoices and receipts.
Review rows¶
List rows, narrow the list with filters, inspect one row, and read its event history. The sequence imports the quarter and walks the read commands:
aeat app ledger listaeat app ledger listACCOUNTING 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 list --filter period=1T --filter year=2026aeat app ledger list --filter period=1T --filter year=2026ACCOUNTING 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 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 app ledger view 71a5db2baeat app ledger view 71a5db2bID 71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518 Date 2026-02-10 Value date 2026-02-10 Amount 1210 Currency EUR Direction INCOMING Description Cobro factura F-2026-001 servicios de consultoria Counterparty - Classification NOT_YET_PROCESSED Business % - Category - Usage ratio id - Taxable base - IVA rate - IVA amount - IVA category - Established in - VAT identified in - IRPF category - Notes - Purchase invoice evidence - Attachments - Lifecycle state ACTIVE Classified by auto Classified at - Classification confidence - Classification reason - Review status pending
aeat app ledger history 71a5db2baeat app ledger history 71a5db2bBucket <profile-id> ID 71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518 Event count 1 2026-04-01T09:00:00+00:00 ledger.transaction.imported 1a59b4ec789420d5ec241c40cf90be91ca7a1d4ca191ceb478a141a48bfa14c3
aeat app ledger track 71a5db2baeat app ledger track 71a5db2bID 71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518 Lifecycle state ACTIVE Created bucket event - import_provider CSV provider import_source movimientos-2026-1t.csv import_ingested_at 2026-04-01T09:00:00+00:00 import_fingerprint 924aad06902b61c5d2c34863ac5d8c8768039a38540cd0235e0308d6be767898
aeat --format json app ledger view 71a5db2baeat --format json app ledger view 71a5db2b{ "active_profile": "docs-sequence-sandbox", "command": "ledger.view", "notices": [], "result": { "bucket_id": "<bucket-id>", "review_status": "pending", "transaction": { "amount": "1210", "attachment_ids": [], "booked_date": "2026-02-10", "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-10", "description": "Cobro factura F-2026-001 servicios de consultoria", "direction": "INCOMING", "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": "71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518", "usage_ratio_id": null, "value_date": "2026-02-10", "value_in_eur": null }, "transaction_id": "71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518" }, "schema_version": "2", "status": "success" }
Confirm the inspected row reads the imported income movement.
For a broader review queue, use ledger review to inspect selected rows and
ledger check to report aggregate ledger anomalies across periods. Both are
local-only:
aeat app ledger review --filter period=1T --filter year=2026aeat app ledger review --filter period=1T --filter year=2026ACCOUNTING LEDGER REVIEW SESSION 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 checkaeat --format json app ledger check{ "active_profile": "docs-sequence-sandbox", "command": "ledger.check", "notices": [], "result": { "bucket_id": "<bucket-id>", "checked_transaction_count": 2, "issues": [ { "detail": "business classification 'NOT_YET_PROCESSED' is not ready for modelo calculation", "reason": "missing_business_classification", "transaction_id": "71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518" }, { "detail": "business classification 'NOT_YET_PROCESSED' is not ready for modelo calculation", "reason": "missing_business_classification", "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d" } ], "link_inconsistencies": [], "periods": [ "2026" ], "ready": false }, "schema_version": "2", "status": "success" }
Confirm the aggregate ledger check runs cleanly.
Export rows for review¶
Export the active ledger to a file. The --year and --period filter keeps the
export aligned with the transaction dates. Exports are review snapshots, not an
edit-and-reimport path:
aeat --format json app ledger export --output ./ledger-2026-q1.csv --year 2026 --period \
1Taeat --format json app ledger export --output ./ledger-2026-q1.csv --year 2026 --period `
1T{ "active_profile": "docs-sequence-sandbox", "command": "ledger.export", "notices": [], "result": { "bucket_event_ids": [ "ec10496135191214d662a70eacf77db3f739a457585f0bb2e8ce45e6bb5805b5" ], "bucket_id": "<bucket-id>", "byte_size": 950, "export_format": "csv", "export_id": "5f0ddcff2e977990b1b5fd3fc6e107cf9b3cb3b5f7ac82e87d072c77fed11cf4", "fieldnames": [ "bucket_id", "transaction_id", "lifecycle_state", "booked_date", "value_date", "effective_date", "amount", "currency", "direction", "counterparty", "description", "source_jurisdiction", "business_classification", "business_pct", "category_id", "taxable_base", "iva_rate", "iva_amount", "iva_category", "counterparty_country", "counterparty_identification_state", "irpf_category", "usage_ratio_id", "prorrata_reference", "purchase_invoice_evidence_id", "attachment_ids", "notes", "created_by", "created_source_command", "value_in_eur", "fx_rate" ], "filename_extension": "csv", "media_type": "text/csv", "output_path": "ledger-2026-q1.csv", "row_count": 2, "rows": [ { "amount": "1210.00", "attachment_ids": "", "booked_date": "2026-02-10", "bucket_id": "<bucket-id>", "business_classification": "NOT_YET_PROCESSED", "business_pct": "", "category_id": "", "counterparty": "", "counterparty_country": "", "counterparty_identification_state": "", "created_by": "", "created_source_command": "", "currency": "EUR", "description": "Cobro factura F-2026-001 servicios de consultoria", "direction": "INCOMING", "effective_date": "2026-02-10", "fx_rate": "", "irpf_category": "", "iva_amount": "", "iva_category": "", "iva_rate": "", "lifecycle_state": "ACTIVE", "notes": "", "prorrata_reference": "", "purchase_invoice_evidence_id": "", "source_jurisdiction": "", "taxable_base": "", "transaction_id": "71a5db2bb891df295bee72544c40497d24d5c8cfc7edab745ce7339dcf8d6518", "usage_ratio_id": "", "value_date": "2026-02-10", "value_in_eur": "" }, { "amount": "605.00", "attachment_ids": "", "booked_date": "2026-02-11", "bucket_id": "<bucket-id>", "business_classification": "NOT_YET_PROCESSED", "business_pct": "", "category_id": "", "counterparty": "", "counterparty_country": "", "counterparty_identification_state": "", "created_by": "", "created_source_command": "", "currency": "EUR", "description": "Compra de material de oficina proveedor local", "direction": "OUTGOING", "effective_date": "2026-02-11", "fx_rate": "", "irpf_category": "", "iva_amount": "", "iva_category": "", "iva_rate": "", "lifecycle_state": "ACTIVE", "notes": "", "prorrata_reference": "", "purchase_invoice_evidence_id": "", "source_jurisdiction": "", "taxable_base": "", "transaction_id": "e3eeac5e306efe4e82a72896e92e7c236245ec85348834b2c10b120c67fe087d", "usage_ratio_id": "", "value_date": "2026-02-11", "value_in_eur": "" } ], "sha256": "0becceaa2ef5f6edba6a89f5fee123b09f1a044d477005dd381cecb52f66213d" }, "schema_version": "2", "status": "success" }
Confirm the ledger exports for the requested period.
aeat app ledger export --output ./ledger-2026.xlsx --export-format xlsx --year 2026 \
--period 0Aaeat app ledger export --output ./ledger-2026.xlsx --export-format xlsx --year 2026 `
--period 0AAdd --export-format xlsx to write an XLSX snapshot instead, and use the annual
token 0A when a whole year is the review scope.
To change saved rows, use ledger update, ledger classify, ledger allocate,
ledger split, or ledger merge.
Update a row¶
Use ledger update for editable transaction fields - date, value date, amount,
direction, currency, counterparty, description, taxable base, IVA rate, IVA
amount, IRPF category, notes, or group label:
aeat --format json app ledger update {transaction_id} --description \
Corrected descriptionaeat --format json app ledger update {transaction_id} --description `
Corrected description{ "active_profile": "docs-sequence-sandbox", "command": "ledger.update", "notices": [], "result": { "bucket_event_ids": [ "51bb581f6eb1806a49fcd5105e639fc5aa44520bae30174e14209ac995f7d355" ], "bucket_id": "<bucket-id>", "review_status": "pending", "transaction": { "amount": "121", "attachment_ids": [], "booked_date": "2026-03-21", "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-03-21", "description": "Corrected description", "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": "86f4d44865f693e51c368c3e8f25a5b9bf7e1acf6089298e885854d661254629", "usage_ratio_id": null, "value_date": null, "value_in_eur": null }, "transaction_id": "86f4d44865f693e51c368c3e8f25a5b9bf7e1acf6089298e885854d661254629" }, "schema_version": "2", "status": "success" }
aeat --format json app ledger update {after_description} --taxable-base 100.00 \
--iva-rate 0.21 --iva-amount 21.00aeat --format json app ledger update {after_description} --taxable-base 100.00 `
--iva-rate 0.21 --iva-amount 21.00{ "active_profile": "docs-sequence-sandbox", "command": "ledger.update", "notices": [], "result": { "bucket_event_ids": [ "6082dd1e06c1a8299d25b7bfa3ac07495b32841016b4dc538a50ccfc9a81744d" ], "bucket_id": "<bucket-id>", "review_status": "pending", "transaction": { "amount": "121", "attachment_ids": [], "booked_date": "2026-03-21", "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-03-21", "description": "Corrected description", "direction": "OUTGOING", "fx_rate": null, "invoice_id": null, "irpf_category": null, "iva_amount": "21", "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": "100", "transaction_id": "86f4d44865f693e51c368c3e8f25a5b9bf7e1acf6089298e885854d661254629", "usage_ratio_id": null, "value_date": null, "value_in_eur": null }, "transaction_id": "86f4d44865f693e51c368c3e8f25a5b9bf7e1acf6089298e885854d661254629" }, "schema_version": "2", "status": "success" }
aeat app ledger update {after_iva} --notes Receipt checked against supplier PDFaeat app ledger update {after_iva} --notes Receipt checked against supplier PDFID 86f4d44865f693e51c368c3e8f25a5b9bf7e1acf6089298e885854d661254629 Date 2026-03-21 Amount 121 Description Corrected description Review status pending
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": "pending", "transaction": { "amount": "121", "attachment_ids": [], "booked_date": "2026-03-21", "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-03-21", "description": "Corrected description", "direction": "OUTGOING", "fx_rate": null, "invoice_id": null, "irpf_category": null, "iva_amount": "21", "iva_category": null, "iva_rate": "0.21", "lifecycle_state": "ACTIVE", "m210_income_classification": null, "modified_at": "2026-04-01T09:00:00+00:00", "notes": "Receipt checked against supplier PDF", "prorrata_reference": null, "purchase_invoice_evidence_id": null, "source_jurisdiction": "ES", "taxable_base": "100", "transaction_id": "86f4d44865f693e51c368c3e8f25a5b9bf7e1acf6089298e885854d661254629", "usage_ratio_id": null, "value_date": null, "value_in_eur": null }, "transaction_id": "86f4d44865f693e51c368c3e8f25a5b9bf7e1acf6089298e885854d661254629" }, "schema_version": "2", "status": "success" }
Confirm the row's description and IVA fields were updated.
An update gives the transaction a new id; an id you wrote down earlier still
resolves in view, history, and track. For the full correction workflow -
splitting, merging, archiving, stashing, removing, and resetting rows - see
Correct mistakes in your ledger.
Attach evidence to a transaction¶
Attach secure purchase evidence to a transaction. The evidence id comes from
aeat app ledger evidence add. The sequence records evidence and an expense,
then attaches one to the other:
aeat app ledger attach {transaction_id} --purchase-invoice-evidence-id {evidence_id}aeat app ledger attach {transaction_id} --purchase-invoice-evidence-id {evidence_id}ID 9ad5e90279a049021db72b53806469870d4739a6d557a47006099b5ce5c9573b Date 2026-03-21 Amount 121 Description Office supplies Review status pending
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": "pending", "transaction": { "amount": "121", "attachment_ids": [], "booked_date": "2026-03-21", "business_classification": "NOT_YET_PROCESSED", "business_pct": null, "category_id": "material_oficina", "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-03-21", "description": "Office supplies", "direction": "OUTGOING", "fx_rate": null, "invoice_id": null, "irpf_category": null, "iva_amount": "21", "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": "6509f06abb0c5756", "source_jurisdiction": "ES", "taxable_base": "100", "transaction_id": "9ad5e90279a049021db72b53806469870d4739a6d557a47006099b5ce5c9573b", "usage_ratio_id": null, "value_date": null, "value_in_eur": null }, "transaction_id": "9ad5e90279a049021db72b53806469870d4739a6d557a47006099b5ce5c9573b" }, "schema_version": "2", "status": "success" }
Confirm the purchase-invoice evidence attached to the transaction.
attach is the single door for purchase evidence. The link command binds a
transaction to a reconciliation-catalogue invoice only.
The link --invoice-id option expects an id from the reconciliation invoice
catalogue (populated by the import and reconcile flows), not an id from aeat app ledger invoice add. See
Attach invoices and receipts for the full evidence and
invoice-record workflow, including the --attachment-id option and its current
limitation.
Pull a document straight from Google Drive into encrypted evidence storage with
evidence pull. This command reaches Google Drive, so it runs against your own
authorized account rather than in the documentation sandbox:
aeat app ledger evidence pull <transaction-id> --source GOOGLE_DRIVE --reference \
<drive-file-id> --note Supplier invoiceaeat app ledger evidence pull <transaction-id> --source GOOGLE_DRIVE --reference `
<drive-file-id> --note Supplier invoiceThe command downloads the Drive file, stores its bytes encrypted with the
transaction, and keeps the original link as provenance. Gmail links, arbitrary
URLs, and Drive files outside the granted scope are refused - evidence always
carries the document itself, never a bare link. For a refused source, download
the document yourself and attach it with aeat app ledger attach --attachment-id.
Fix a wrong row¶
Splitting a mixed movement into parts, merging a wrong split back, and archiving, stashing, removing, or resetting rows are all corrections. Correct mistakes in your ledger owns that workflow, with an example for each command and guidance on picking the least destructive fix.
Classify rows¶
Classify rows before calculation. At a minimum, imported business rows need a business/personal/mixed decision, and expense rows need a category:
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 imported expense is classified as business.
Classify transactions owns the full workflow - bulk CSV classification, mixed-use allocation, tax fields, stored rules, and LLM-assisted suggestions.
Check readiness for a filing period¶
Run preflight before calculating a modelo, then check the overall ledger state. Preflight looks at each record inside the period and flags anything still missing before any sums are trusted - a missing classification, category, base, IVA amount, IVA rate, split reference, or unconvertible currency:
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 the period's readiness is reported for the classified quarter.
The check changes nothing; it names the rows that are not ready so you fix the raw material before trusting any total. Continue to calculation only when the active profile and target period are ready enough for the modelo you are preparing.
For calculation review in Google Sheets, see Review calculations with Google Sheets. That workflow exports a modelo calculation surface to Sheets; it is separate from ledger CSV/XLSX export.
If a command stops with an error¶
If a command reports that no profile is active, the period is invalid, or the ledger is not ready, use Diagnose and repair your local setup.
Next steps¶
Import, export, and evidence - understand what imported rows mean and how they differ from tax facts and filing evidence.