# Ledger Archive

The ledger archive provides long-term storage of historical ledger data in a compressed format, reducing the size of the live ledger table while preserving full history for auditing and reconciliation.

## Why Archive?

The `ledger` table grows indefinitely as transactions accumulate. High-volume accounts can reach millions of rows, potentially degrading query performance over time. Archiving moves old ledger data into compressed records, each holding up to **1,000 ledger lines**.

## How It Works

Archiving is **client-triggered** — you decide when to archive and what date cutoff to use. The system never archives automatically.

### Archive Request

```bash
curl -X POST http://<host>:8080/ledger/archive \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: ak_..." \
  -H "X-Api-Secret: sk_..." \
  -d '{
    "before": "2026-07-01"
  }'
```

This archives all ledger lines with `created_at` before July 1, 2026, across **all accounts**.

**Rules:**

* `before` cannot be the current date or a future date
* All accounts are archived with the same cutoff — you don't specify per-account dates

### Archive Response

```json
{
  "before": "2026-07-01",
  "accounts_affected": 1847,
  "records_created": 312,
  "records_updated": 48,
  "lines_archived": 284930,
  "lines_remaining": 41200
}
```

## Record Packing

Archive records are packed to maximize density:

* Each record holds up to **1,000 ledger lines**
* On subsequent archives, the system fills the last existing record for each account before creating new ones
* **All records are full (1,000 lines) except possibly the last one per account**
* A record with fewer than 1,000 lines that is not the last one per account indicates a problem

This ensures zero fragmentation and predictable record sizes.

## Integrity Gate

Before any archiving begins, the system runs a **full integrity validation** across all entities (accounts, journal entries, ledger, and existing archive records). If any integrity violation is detected, the entire archive operation is rejected.

This prevents archiving from being used to hide evidence of data tampering.

## Idempotent by Nature

Each account is processed independently. If the operation fails midway through, already-archived accounts are safe. You can resubmit the same request — accounts with no remaining lines before the cutoff are skipped automatically.

## Archive Record Fields

| Field             | Type       | Description                                       |
| ----------------- | ---------- | ------------------------------------------------- |
| `id`              | UUID       | Unique identifier for this archive record         |
| `account_id`      | UUID       | The account this record belongs to                |
| `asset`           | String     | Currency code                                     |
| `version_from`    | Integer    | First `account_version` in this record            |
| `version_to`      | Integer    | Last `account_version` in this record             |
| `created_at_from` | Timestamp  | Earliest `created_at` among lines in this record  |
| `created_at_to`   | Timestamp  | Latest `created_at` among lines in this record    |
| `balance_before`  | Integer    | Balance just before the first line in this record |
| `balance_after`   | Integer    | Balance after the last line in this record        |
| `line_count`      | Integer    | Number of ledger lines in this record (max 1,000) |
| `lines`           | JSON Array | The ledger lines themselves                       |

## Reading Archived Ledger

```bash
curl "http://<host>:8080/account/<id>/ledger/archive?from=2026-01-01&to=2026-06-30&cursor=0" \
  -H "X-Api-Key: ak_..." \
  -H "X-Api-Secret: sk_..."
```

### Query Parameters

| Parameter | Type    | Description                                               |
| --------- | ------- | --------------------------------------------------------- |
| `from`    | String  | Start date (`YYYY-MM-DD`), inclusive                      |
| `to`      | String  | End date (`YYYY-MM-DD`), inclusive                        |
| `cursor`  | Integer | `version_to` from the previous response (0 on first call) |

Returns **one record per call** (each record can be 300-400KB with 1,000 lines).

### Response

```json
{
  "account_id": "019702a0-...",
  "version_from": 1,
  "version_to": 1000,
  "created_at_from": "2025-12-28T00:00:00Z",
  "created_at_to": "2026-01-05T23:59:00Z",
  "balance_before": 0,
  "balance_after": 152300,
  "line_count": 1000,
  "lines": [ ... ],
  "next_cursor": 1000,
  "has_more": true
}
```

Use `next_cursor` as the `cursor` parameter for the next call. Continue until `has_more` is `false`.

{% hint style="warning" %}
Records at date boundaries may contain lines outside the requested date range. Filter locally on the client side if you need exact date filtering.
{% endhint %}

## Best Practices

* **Archive during off-peak hours** — archiving processes all qualifying accounts and involves significant I/O
* **Choose a conservative cutoff** — archive data you're confident you won't need to query frequently
* **Monitor your ledger table size** — archive when the live ledger becomes large enough to affect query performance
* **The live ledger continues to work** — `GET /account/:id/ledger` always returns current data; use the archive endpoint for historical data


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://entrytarget.gitbook.io/docs/concepts/ledger-archive.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
