Correct mistakes in your ledger

Fix wrong transactions in your ledger without losing track of what changed. Every correction leaves a visible history entry, so you can always see what a transaction looked like before and after. Everything happens on your computer - nothing is sent anywhere.

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.

To find the transaction you want to fix, list your transactions and view one in detail. The sequence below records an example expense, lists the ledger, and inspects that row:

1Record an example expense you will correct in the sections below.
aeat --format json app ledger add --date 2026-03-15 --amount 210.00 --direction OUTGOING \
  --description Silla de oficina --idempotency-key correct-find
aeat --format json app ledger add --date 2026-03-15 --amount 210.00 --direction OUTGOING `
  --description Silla de oficina --idempotency-key correct-find
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.add",
  "notices": [],
  "result": {
    "bucket_event_ids": [
      "a9ef0aa32d83010e35c72d35d6cc793ade13766f38979a9ae358646f1064352f"
    ],
    "bucket_id": "<bucket-id>",
    "review_status": "pending",
    "transaction": {
      "amount": "210",
      "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": "Silla de oficina",
      "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": "f83add280832e5cbcbfc1da6432f5e6a7e02eb78ba74fc265eb483b805ee7afb",
      "usage_ratio_id": null,
      "value_date": null,
      "value_in_eur": null
    },
    "transaction_id": "f83add280832e5cbcbfc1da6432f5e6a7e02eb78ba74fc265eb483b805ee7afb"
  },
  "schema_version": "2",
  "status": "success"
}
2List your transactions to find the one to fix.
aeat app ledger list
aeat app ledger list
ACCOUNTING LEDGER TRANSACTIONS
id	full_id	date	amount	description	IVA category	review_status
f83add28	f83add280832e5cbcbfc1da6432f5e6a7e02eb78ba74fc265eb483b805ee7afb	2026-03-15	210	Silla de oficina		pending
3Inspect one transaction in detail before changing it.
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": "210",
      "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": "Silla de oficina",
      "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": "f83add280832e5cbcbfc1da6432f5e6a7e02eb78ba74fc265eb483b805ee7afb",
      "usage_ratio_id": null,
      "value_date": null,
      "value_in_eur": null
    },
    "transaction_id": "f83add280832e5cbcbfc1da6432f5e6a7e02eb78ba74fc265eb483b805ee7afb"
  },
  "schema_version": "2",
  "status": "success"
}

Confirm the inspected transaction is the one you want to fix.

The view command reports the id, amount, direction, description, and lifecycle state. The transactions guide covers listing and filtering in depth.

Pick your fix

  • If one transaction has a wrong amount, date, or text, update it.

  • If a transaction should not exist at all, remove it.

  • If the same purchase was imported twice, remove the duplicate - or archive it to keep a deliberate trace of it.

  • If one payment covers two different things, split it.

  • If you split something and want it back together, merge the parts.

  • If you’re unsure about a transaction and want it out of the way, stash it.

  • If you want to keep a transaction in history but out of everyday lists, archive it.

  • If you stashed or archived a transaction by mistake, restore it to active.

Update fields on a transaction

Change one or more fields directly. The sequence records a chair at the wrong price, corrects the amount and description, and confirms the correction:

1Record a transaction with a wrong price to correct.
aeat --format json app ledger add --date 2026-03-15 --amount 100.00 --direction OUTGOING \
  --description Office chair --idempotency-key correct-update
aeat --format json app ledger add --date 2026-03-15 --amount 100.00 --direction OUTGOING `
  --description Office chair --idempotency-key correct-update
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.add",
  "notices": [],
  "result": {
    "bucket_event_ids": [
      "47c494e7c2a1631efad4835b3c50110ccfda63015482d65fef4f0b83f8dd1c61"
    ],
    "bucket_id": "<bucket-id>",
    "review_status": "pending",
    "transaction": {
      "amount": "100",
      "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": "Office chair",
      "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": "1a9106f8f6783eaf5ba09478eeb3bcec6188caf02d136a7cdd9770bcd6e7830d",
      "usage_ratio_id": null,
      "value_date": null,
      "value_in_eur": null
    },
    "transaction_id": "1a9106f8f6783eaf5ba09478eeb3bcec6188caf02d136a7cdd9770bcd6e7830d"
  },
  "schema_version": "2",
  "status": "success"
}
2Change the amount and description in one command.
aeat app ledger update {transaction_id} --amount 121.00 --description \
  Office chair, corrected price
aeat app ledger update {transaction_id} --amount 121.00 --description `
  Office chair, corrected price
ID	59316515102ea30c11d09b68fccd42fd4ed6b385f8fe1324412724fb1827dfe5
Date	2026-03-15
Amount	121
Description	Office chair, corrected price
Review status	pending
3The original id still resolves; view it to confirm the correction.
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-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": "Office chair, corrected price",
      "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": "59316515102ea30c11d09b68fccd42fd4ed6b385f8fe1324412724fb1827dfe5",
      "usage_ratio_id": null,
      "value_date": null,
      "value_in_eur": null
    },
    "transaction_id": "59316515102ea30c11d09b68fccd42fd4ed6b385f8fe1324412724fb1827dfe5"
  },
  "schema_version": "2",
  "status": "success"
}

Confirm the update replaced the amount and description.

Each flag fully replaces that field - write the complete new value, not an addition to the old one. Write the amount as a positive figure - the direction field carries whether money came in or went out, and a negative amount is refused. The updatable fields are: date, value-date, amount, direction, currency, counterparty, description, taxable-base, iva-rate, iva-amount, irpf-category, notes, and group.

An update gives the transaction a new ID - the update output prints it. You don’t have to track the change for read commands: an ID you wrote down before the update still answers in history, view, and track, resolving to the corrected transaction, exactly as the view above does. For a further mutation - another update, classify, or archive - use the current ID from the update output or from list, because those commands act on the live transaction.

Update works on active transactions only. Archived and stashed transactions refuse it, as does a split parent - the active parts of a split can be updated normally.

Remove a transaction

Remove deletes a transaction from your active records. Preview it first with --dry-run, then remove it for real. The removed id no longer resolves, which is how the sequence confirms the deletion:

1Record a transaction imported from the wrong file.
aeat --format json app ledger add --date 2026-03-15 --amount 60.50 --direction OUTGOING \
  --description Wrong import --idempotency-key correct-remove
aeat --format json app ledger add --date 2026-03-15 --amount 60.50 --direction OUTGOING `
  --description Wrong import --idempotency-key correct-remove
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.add",
  "notices": [],
  "result": {
    "bucket_event_ids": [
      "8b33ed95365478e1093bdc08e4960210b7eb3fda5fe8f7de1144c1a9c47a8688"
    ],
    "bucket_id": "<bucket-id>",
    "review_status": "pending",
    "transaction": {
      "amount": "60.5",
      "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": "Wrong import",
      "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": "1caacc8087e969e8648cc8618626fb93510b89a62186b1854f9a1893813869eb",
      "usage_ratio_id": null,
      "value_date": null,
      "value_in_eur": null
    },
    "transaction_id": "1caacc8087e969e8648cc8618626fb93510b89a62186b1854f9a1893813869eb"
  },
  "schema_version": "2",
  "status": "success"
}
2Preview the removal without deleting anything.
aeat app ledger remove {transaction_id} --reason wrong file imported --dry-run
aeat app ledger remove {transaction_id} --reason wrong file imported --dry-run
Bucket	<profile-id>
ID	1caacc8087e969e8648cc8618626fb93510b89a62186b1854f9a1893813869eb
Removed	False
DRY RUN MODE	True
3Remove it for real.
aeat app ledger remove {transaction_id} --reason wrong file imported --yes
aeat app ledger remove {transaction_id} --reason wrong file imported --yes
Bucket	<profile-id>
ID	1caacc8087e969e8648cc8618626fb93510b89a62186b1854f9a1893813869eb
Removed	True
DRY RUN MODE	False
4Confirm the id no longer resolves.
aeat --format json app ledger view {transaction_id}
aeat --format json app ledger view {transaction_id}
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.view",
  "error": {
    "action": {
      "action": null,
      "argument_bindings": [],
      "conditionality": "not_applicable",
      "evidence": [
        {
          "condition_id": "cli.ledger.transaction_id.resolves",
          "evidence_id": "cli.ledger.transaction_id.resolves.observation",
          "provenance": "runtime_observation",
          "values": {
            "transaction_id_resolves": false
          }
        }
      ],
      "failed_condition_id": "cli.ledger.transaction_id.resolves",
      "missing_argument_names": [],
      "no_recovery_outcome": "operator_decision"
    },
    "category": "REFUSED",
    "code": "REFUSED_FINANCIAL_LEDGER_TRANSACTION_ID_PREFIX",
    "context": {
      "prefix": "'1caacc8087e969e8648cc8618626fb93510b89a62186b1854f9a1893813869eb'"
    },
    "message": "no transaction matches id prefix '1caacc8087e969e8648cc8618626fb93510b89a62186b1854f9a1893813869eb'",
    "retryable": false,
    "runbook_id": null,
    "trace_id": null
  },
  "notices": [],
  "schema_version": "2",
  "status": "error"
}

Confirm the removed transaction no longer resolves.

A removed transaction is gone from your active records: the final view refuses because the id no longer names an active row.

Split one transaction into parts

When one payment covers two different things - for example, a card payment that mixes business and personal items - split it into parts. Amounts and descriptions pair up one per part: the first amount goes with the first description, and so on:

1Record a card payment that mixes business and personal items.
aeat --format json app ledger add --date 2026-03-15 --amount 121.00 --direction OUTGOING \
  --description Mixed receipt --idempotency-key correct-split
aeat --format json app ledger add --date 2026-03-15 --amount 121.00 --direction OUTGOING `
  --description Mixed receipt --idempotency-key correct-split
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.add",
  "notices": [],
  "result": {
    "bucket_event_ids": [
      "9f5e7d2af0b80902321e3b1202a64f33db90510f94d37b6ac8a1faae0c89d25c"
    ],
    "bucket_id": "<bucket-id>",
    "review_status": "pending",
    "transaction": {
      "amount": "121",
      "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": "Mixed receipt",
      "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": "e55d6600ead7d9490cb4774a0de8f8e9254866b0015b5c6898c68569e8d7a6e9",
      "usage_ratio_id": null,
      "value_date": null,
      "value_in_eur": null
    },
    "transaction_id": "e55d6600ead7d9490cb4774a0de8f8e9254866b0015b5c6898c68569e8d7a6e9"
  },
  "schema_version": "2",
  "status": "success"
}
2Split the payment into two parts.
aeat --format json app ledger split {transaction_id} --child-amount 100.00 \
  --child-description office supplies --child-amount 21.00 --child-description \
  personal items --reason mixed receipt --yes
aeat --format json app ledger split {transaction_id} --child-amount 100.00 `
  --child-description office supplies --child-amount 21.00 --child-description `
  personal items --reason mixed receipt --yes
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.split",
  "notices": [],
  "result": {
    "bucket_event_id": "2960d40c4f90dbaa25b1c462ce52210f4b2cc4ab1904c6c78c08739e821fbf1b",
    "bucket_id": "<bucket-id>",
    "child_transaction_ids": [
      "9cc7a2639a30fcead52f62683cdc1c627a8b47cb43ff333f01b19e7f37245b49",
      "0bba86e710bdb3ccf97cd1cf82d62a5011a7107989ee76648f8ef8932c28ba0e"
    ],
    "child_transactions": [
      {
        "display_id": "9cc7a263",
        "full_id": "9cc7a2639a30fcead52f62683cdc1c627a8b47cb43ff333f01b19e7f37245b49"
      },
      {
        "display_id": "0bba86e7",
        "full_id": "0bba86e710bdb3ccf97cd1cf82d62a5011a7107989ee76648f8ef8932c28ba0e"
      }
    ],
    "classified_child_count": null,
    "llm": null,
    "parent_amount": null,
    "parent_transaction_id": "e55d6600ead7d9490cb4774a0de8f8e9254866b0015b5c6898c68569e8d7a6e9",
    "persisted": null,
    "proposed_children": null,
    "provenance": null,
    "provider": null,
    "reason": null,
    "split_group_id": "49e46bf12630b536b609999a5502582c94bc0faefcbba41cf784f89552823662"
  },
  "schema_version": "2",
  "status": "success"
}
3Confirm the first part is an active transaction of its own.
aeat --format json app ledger view {first_part}
aeat --format json app ledger view {first_part}
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.view",
  "notices": [],
  "result": {
    "bucket_id": "<bucket-id>",
    "review_status": "pending",
    "transaction": {
      "amount": "100",
      "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": "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": "9cc7a2639a30fcead52f62683cdc1c627a8b47cb43ff333f01b19e7f37245b49",
      "usage_ratio_id": null,
      "value_date": null,
      "value_in_eur": null
    },
    "transaction_id": "9cc7a2639a30fcead52f62683cdc1c627a8b47cb43ff333f01b19e7f37245b49"
  },
  "schema_version": "2",
  "status": "success"
}

Confirm the split produced two active child parts.

The original transaction becomes the split parent, and the parts carry the balance from then on. The split output prints one child_transactions row per part, each with a short display_id and a full full_id. Copy those ids - the merge command needs them to undo the split.

Merge split parts back

To undo a split, merge the parts back together using the child ids the split printed. Name every sibling part - the command refuses a partial merge. The sequence splits a payment, then merges the parts into one fresh transaction:

1Merge the two parts back into one transaction, naming every sibling.
aeat --format json app ledger merge --child-id {first_child} --child-id {second_child} \
  --reason undo split --yes
aeat --format json app ledger merge --child-id {first_child} --child-id {second_child} `
  --reason undo split --yes
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.merge",
  "notices": [],
  "result": {
    "bucket_event_id": "24fa3aac51e5315bbb008dcbc57b80fdc41b292a4d2e504303e54e6c21354591",
    "bucket_id": "<bucket-id>",
    "merged_transaction_id": "afc12ac601d050659efe0abace313167f275923e77ba6b0a4ead868f32d7cdd9",
    "parent_transaction_id": "3cda9f1229ee04269a70bb6705dafeff1de2f9b14f1bfcefacba4ae277b20a9d",
    "source_child_ids": [
      "63c3f9245937ab54232f067804fc12248abcbb1a5f9d93e9433313f8bf74b23d",
      "e0504b924f0b4500f0be1c70fe2958279ff9d9d0e5f61c4c66615fe9ed65ae84"
    ],
    "split_group_id": "ea58900b8c1962062494a7fb1c80418936a96ae53f2e402af33f8b212fb055c0"
  },
  "schema_version": "2",
  "status": "success"
}
2Confirm the merged transaction is active and carries the full amount.
aeat --format json app ledger view {merged}
aeat --format json app ledger view {merged}
{
  "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-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": "Split to undo",
      "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": "afc12ac601d050659efe0abace313167f275923e77ba6b0a4ead868f32d7cdd9",
      "usage_ratio_id": null,
      "value_date": null,
      "value_in_eur": null
    },
    "transaction_id": "afc12ac601d050659efe0abace313167f275923e77ba6b0a4ead868f32d7cdd9"
  },
  "schema_version": "2",
  "status": "success"
}

Confirm the merge produced a single active transaction carrying the full amount.

The parts and the original parent move to history, and the merge creates a fresh transaction in their place. If you no longer have the split output, the parts are active rows: run aeat app ledger list and read their ids from the listing.

Stash a transaction you are unsure about

Stash sets a transaction aside for later. A stashed transaction is kept out of ordinary work. The sequence stashes a row and confirms its new lifecycle state:

1Record a transaction you are not ready to resolve.
aeat --format json app ledger add --date 2026-03-15 --amount 80.00 --direction OUTGOING \
  --description Awaiting invoice --idempotency-key correct-stash
aeat --format json app ledger add --date 2026-03-15 --amount 80.00 --direction OUTGOING `
  --description Awaiting invoice --idempotency-key correct-stash
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.add",
  "notices": [],
  "result": {
    "bucket_event_ids": [
      "78ad404abaedb72ff65685f682bb8eeb58032ac35d5553aabd48810cc6cbea06"
    ],
    "bucket_id": "<bucket-id>",
    "review_status": "pending",
    "transaction": {
      "amount": "80",
      "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": "Awaiting invoice",
      "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": "f5c6e7a8fce9960b36a29df9e59c7954affef5dc4bf50cd6a0aaaebc3eed8c22",
      "usage_ratio_id": null,
      "value_date": null,
      "value_in_eur": null
    },
    "transaction_id": "f5c6e7a8fce9960b36a29df9e59c7954affef5dc4bf50cd6a0aaaebc3eed8c22"
  },
  "schema_version": "2",
  "status": "success"
}
2Set it aside for later.
aeat app ledger stash {transaction_id} --reason waiting for invoice --yes
aeat app ledger stash {transaction_id} --reason waiting for invoice --yes
ID	f5c6e7a8fce9960b36a29df9e59c7954affef5dc4bf50cd6a0aaaebc3eed8c22
Date	2026-03-15
Amount	80
Description	Awaiting invoice
Review status	pending
3Confirm the lifecycle state now reads STASHED.
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": "80",
      "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": "Awaiting invoice",
      "direction": "OUTGOING",
      "fx_rate": null,
      "invoice_id": null,
      "irpf_category": null,
      "iva_amount": null,
      "iva_category": null,
      "iva_rate": null,
      "lifecycle_state": "STASHED",
      "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": "f5c6e7a8fce9960b36a29df9e59c7954affef5dc4bf50cd6a0aaaebc3eed8c22",
      "usage_ratio_id": null,
      "value_date": null,
      "value_in_eur": null
    },
    "transaction_id": "f5c6e7a8fce9960b36a29df9e59c7954affef5dc4bf50cd6a0aaaebc3eed8c22"
  },
  "schema_version": "2",
  "status": "success"
}

Confirm the transaction moved to the stashed state.

Use stash for a row you have not resolved yet and archive for a row you have deliberately set aside, such as a confirmed duplicate. Both are reversible: restore returns the row to active. The stash command prints the transaction’s fields but not its new lifecycle state, so view is how you confirm the change took effect.

Archive a transaction

Archive keeps a transaction in history but out of ordinary work - it’s the right choice for duplicates you want to keep a deliberate trace of. The sequence archives a duplicate row and confirms the state change:

1Record a duplicate row you want to keep a trace of.
aeat --format json app ledger add --date 2026-03-15 --amount 80.00 --direction OUTGOING \
  --description Duplicate import --idempotency-key correct-archive
aeat --format json app ledger add --date 2026-03-15 --amount 80.00 --direction OUTGOING `
  --description Duplicate import --idempotency-key correct-archive
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.add",
  "notices": [],
  "result": {
    "bucket_event_ids": [
      "23efbc39a82a4a3977431bce885841629c5b7721e681921b8b70c0b9d90586f1"
    ],
    "bucket_id": "<bucket-id>",
    "review_status": "pending",
    "transaction": {
      "amount": "80",
      "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": "Duplicate import",
      "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": "a095fd3caed8beeb0a33806f3b456822e31378e214e89067227d9f2fc6d0d6b0",
      "usage_ratio_id": null,
      "value_date": null,
      "value_in_eur": null
    },
    "transaction_id": "a095fd3caed8beeb0a33806f3b456822e31378e214e89067227d9f2fc6d0d6b0"
  },
  "schema_version": "2",
  "status": "success"
}
2Archive it out of ordinary work.
aeat app ledger archive {transaction_id} --reason duplicate imported row --yes
aeat app ledger archive {transaction_id} --reason duplicate imported row --yes
ID	a095fd3caed8beeb0a33806f3b456822e31378e214e89067227d9f2fc6d0d6b0
Date	2026-03-15
Amount	80
Description	Duplicate import
Review status	pending
3Confirm the lifecycle state now reads ARCHIVED.
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": "80",
      "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": "Duplicate import",
      "direction": "OUTGOING",
      "fx_rate": null,
      "invoice_id": null,
      "irpf_category": null,
      "iva_amount": null,
      "iva_category": null,
      "iva_rate": null,
      "lifecycle_state": "ARCHIVED",
      "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": "a095fd3caed8beeb0a33806f3b456822e31378e214e89067227d9f2fc6d0d6b0",
      "usage_ratio_id": null,
      "value_date": null,
      "value_in_eur": null
    },
    "transaction_id": "a095fd3caed8beeb0a33806f3b456822e31378e214e89067227d9f2fc6d0d6b0"
  },
  "schema_version": "2",
  "status": "success"
}

Confirm the duplicate moved to the archived state.

Like stash, the command prints the transaction’s fields but not its new lifecycle state, so view confirms the row now reads ARCHIVED.

Restore a stashed or archived transaction

If you stashed or archived a transaction by mistake, restore it to active. Restore is the inverse of stash and archive: the row returns to your everyday lists and totals. The sequence stashes a row and then restores it:

1Return it to your everyday lists and totals.
aeat app ledger restore {transaction_id} --reason stashed by mistake --yes
aeat app ledger restore {transaction_id} --reason stashed by mistake --yes
ID	d74c37a7d906824ef0171222e6c84b31dbcbcf5ed11806ce7864ff3db1267332
Date	2026-03-15
Amount	80
Description	Stashed by mistake
Review status	pending
2Confirm the lifecycle state is ACTIVE again.
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": "80",
      "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": "Stashed by mistake",
      "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": "d74c37a7d906824ef0171222e6c84b31dbcbcf5ed11806ce7864ff3db1267332",
      "usage_ratio_id": null,
      "value_date": null,
      "value_in_eur": null
    },
    "transaction_id": "d74c37a7d906824ef0171222e6c84b31dbcbcf5ed11806ce7864ff3db1267332"
  },
  "schema_version": "2",
  "status": "success"
}

Confirm the restored transaction is active again.

Restore accepts the same id prefix the other commands accept. To recover several rows stashed by mistake, restore each one by id - you do not need to reset the whole ledger. List does not have a stashed-only filter, so identify the stashed rows from the ids you stashed, or from each row’s lifecycle state shown by view.

Restore refuses a row that is already active, and it refuses a row whose period you have already filed - restoring it would change the inputs behind a return you have presented. Restore one of these only after you have corrected the filing through an amendment.

Review what changed

Every correction is recorded. To see every action on a transaction in order, run ledger history. The sequence splits a payment, then reads the history with the sibling flag to follow the whole split family:

1List every action on the transaction in order.
aeat app ledger history {transaction_id}
aeat app ledger history {transaction_id}
Bucket	<profile-id>
ID	1fa07beedceb057f55a3aab56aa756e9dab983c332573ee6bdb1e77bb0e16570
Event count	2
2026-04-01T09:00:00+00:00	ledger.transaction.split	0dd721341b0758df0aa4baaab3e24ad7dd79c3a2f90f5f2fc17856dfe491a21f
2026-04-01T09:00:00+00:00	ledger.transaction.created	808c7c37fdc6678905928147c14d45cb7e28450f8c87c917c27a3b61f6406388
2Follow the whole split family with the sibling flag.
aeat --format json app ledger history {transaction_id} --include-split-siblings
aeat --format json app ledger history {transaction_id} --include-split-siblings
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.history",
  "notices": [],
  "result": {
    "bucket_id": "<bucket-id>",
    "event_count": 2,
    "events": [
      {
        "actor": "<profile-id>",
        "bucket_id": "<bucket-id>",
        "event_id": "0dd721341b0758df0aa4baaab3e24ad7dd79c3a2f90f5f2fc17856dfe491a21f",
        "event_type": "ledger.transaction.split",
        "object_id": "1fa07beedceb057f55a3aab56aa756e9dab983c332573ee6bdb1e77bb0e16570",
        "object_type": "ledger_transaction",
        "occurred_at": "2026-04-01T09:00:00Z",
        "payload": {
          "child_count": "2",
          "parent_transaction_id": "1fa07beedceb057f55a3aab56aa756e9dab983c332573ee6bdb1e77bb0e16570",
          "reason": "mixed receipt",
          "source_command": "aeat app ledger split",
          "split_group_id": "4d2d96d6579ac45716e2561a4bc5e7c73876e0a76843db90f5045ebc6dc7a026"
        },
        "payload_version": 1
      },
      {
        "actor": "<profile-id>",
        "bucket_id": "<bucket-id>",
        "event_id": "808c7c37fdc6678905928147c14d45cb7e28450f8c87c917c27a3b61f6406388",
        "event_type": "ledger.transaction.created",
        "object_id": "1fa07beedceb057f55a3aab56aa756e9dab983c332573ee6bdb1e77bb0e16570",
        "object_type": "ledger_transaction",
        "occurred_at": "2026-04-01T09:00:00Z",
        "payload": {
          "amount": "121.00",
          "currency": "EUR",
          "direction": "OUTGOING",
          "source_command": "aeat app ledger add"
        },
        "payload_version": 1
      }
    ],
    "transaction_id": "1fa07beedceb057f55a3aab56aa756e9dab983c332573ee6bdb1e77bb0e16570"
  },
  "schema_version": "2",
  "status": "success"
}

Confirm the history records the transaction's events in order.

The history lists each action in order with its timestamp and event reference. Details such as the reason and the new values are in the JSON output. To see a value before a change, read the earlier events in the history. The CLI reference covers every field the history shows.

Evidence and corrections

An attached evidence record - a receipt or invoice - is not deleted when you correct a transaction. After a split or merge, check the new transactions and re-attach evidence where needed. The evidence guide covers attaching and checking evidence.

Start over as a last resort

If the ledger is beyond repair - for example, after importing the wrong files repeatedly - clear it and rebuild. Preview first, then confirm. The sequence records a row, previews the reset, clears the ledger, and confirms nothing remains:

1Preview the reset without clearing anything.
aeat app ledger reset --reason re-importing all statements --dry-run
aeat app ledger reset --reason re-importing all statements --dry-run
Bucket	<profile-id>
Rows	1
Reset	False
DRY RUN MODE	True
2Clear the whole ledger for the active profile.
aeat app ledger reset --reason re-importing all statements --yes
aeat app ledger reset --reason re-importing all statements --yes
Bucket	<profile-id>
Rows	1
Reset	True
DRY RUN MODE	False
3Confirm no transactions remain.
aeat --format json app ledger list
aeat --format json app ledger list
{
  "active_profile": "docs-sequence-sandbox",
  "command": "ledger.list",
  "notices": [],
  "result": {
    "bucket_id": "<bucket-id>",
    "limit": null,
    "offset": 0,
    "rows": [],
    "shown": 0,
    "total": 0,
    "truncated": false
  },
  "schema_version": "2",
  "status": "success"
}

Confirm the reset cleared the active ledger.

Reset clears the whole ledger for the active profile. Use the transactions guide to rebuild it from your statements.

Where to get help

If a command refuses or fails, check the troubleshooting guide. Unfamiliar terms are explained in the glossary. Before sharing command output with anyone, strip tax identifiers such as your NIF, CIF, DNI, NIE, or NII.

Next steps