> ## Documentation Index
> Fetch the complete documentation index at: https://docs.checkfu.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Export retained Session and audit records

> Export retained Session events and Audit records without overstating replay, signing, authorization, or erasure guarantees.

Checkfu exposes separate export surfaces for separate authorities:

| Export | Authority it projects |
| - | - |
| Session export | Retained Session event-log positions and content |
| Session context ledger | Rebuildable context and compaction accounting |
| Trajectory export | Selected positions of an authorized Session, with a quality receipt |
| Audit export | Governance and effect-disposition records |

None of these is a second runtime authority. The Session event log remains
execution truth, Usage remains metering truth, and Audit remains governance
truth.

<Warning>
  A typed export route is not proof that its parent capability is live for your
  deployment, Workspace, region, or retention mode. Check
  [capability status](/getting-started/status) before making export part of a
  contractual recovery or compliance workflow.
</Warning>

<Note>
  Plain HTTP against the Checkfu API needs no private package.
  The documented path is usable as written for an admitted Workspace.
  Confirm [capability status](/getting-started/status) before making availability part of your application's contract.
</Note>

## Export one retained Session

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --output session-export.json \
  "https://api.checkfu.com/v1/sessions/$SESSION_ID/export" \
  --header "Authorization: Bearer $CHECKFU_API_KEY" \
  --header "Checkfu-Version: 2026-08-31"
```

`GET /v1/sessions/{id}/export` streams a bounded document. The export freezes an
`end_seq`, reads retained positions in order, and stops when the client
disconnects.

The document identifies its own format and wire version and includes:

* Session and Workspace provenance;
* retained event envelopes through `end_seq`; and
* explicit unavailable positions for content that is shredded or omitted
  under ZDR.

Sequence accounting lets an offline reader detect a missing position within
the exported range. It does not prove that no later events exist, that every
provider effect completed, or that the document is cryptographically authentic.

### What "replay" means here

A standard-retention export can replay the retained event tape structurally:
an offline reader can rebuild the presentation represented by the included
events and preserve unavailable positions. It is not a live Session recovery
bundle. It does not recreate omitted content, provider state, actor leases,
runtime placement, or an uncertain external effect.

Under ZDR, execution content that never entered durable custody cannot be
exported. The export must identify the unavailable position rather than
fabricating a transcript.

## Read the context ledger

`GET /v1/sessions/{id}/ledger` projects context accounting such as the frozen
AgentVersion, loaded capability references, token counts, compactions, and
condensations. It is rebuildable from retained Session truth and does not
replace the event log.

The ledger is not authoritative Usage. Use `GET /v1/usage` for Budget,
quota, and billing settlement.

## Export Audit

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request POST https://api.checkfu.com/v1/audit/export \
  --header "Authorization: Bearer $CHECKFU_API_KEY" \
  --header "Checkfu-Version: 2026-08-31" \
  --header "Content-Type: application/json" \
  --data '{
    "after": 0,
    "limit": 1000
  }'
```

Audit records connect authenticated identity, permission, policy, approval,
revocation, and observed effect disposition. Export in ascending order and
continue with `next_after`.

The SDK and CLI Audit verifiers accept only current `checkfu.audit.v2` chained
records. They reject audit-v1 records and unhashed records rather than
converting or skipping them. The canonical subject must match the exported
Workspace; resumed CLI checkpoints must account for every processed record
as chained. They recompute canonical record hashes and predecessor links. A valid
unfiltered chain proves that the exported canonical records are mutually
consistent. It does not prove:

* that an export is complete, whether filtered or unfiltered;
* that the supplied records are authentic source records;
* that every external provider statement is true;
* that an indeterminate provider effect succeeded or failed;
* that a Session export is authentic.

Do not describe a successful Audit verification as provider verification or
regulatory compliance.

The verifiers receive records and local continuation state, without an
independently trusted terminal count, hash, or source anchor. A shorter valid
prefix or an internally consistent replacement can therefore pass these
checks. Establishing completeness or source authenticity requires independent
trusted evidence beyond this result.

An incompatible saved SDK verifier version or unhashed-prefix state is refused
before any page is examined, including an empty page. That result reports
`incompatible_verification_state` with `broken_at_sequence: null`; it does not
advance or convert the saved state.

Current SDK state carries `state_version: "checkfu.audit-verifier.v1"`, separate
from the record's `checkfu.audit.v2` hash format. CLI checkpoints use
`schema_version: 2`. Checkpoints from the predecessor verifier are unsupported;
start a complete export with a new checkpoint instead of editing its version
marker or resuming an old prefix.

## Session Bundle

`GET /v1/sessions/{id}/bundle` returns a signed `checkfu.session-bundle`
(schema version 3). It freezes one sequence frontier, then streams the body:
one pass reads the log page by page to compute every section digest and sign
the manifest and integrity statements, and a second pass re-reads the same
frozen pages to release the exact bytes it signed. Neither pass holds the
whole history in memory. If retention or deletion changes a position between
the two passes, the body fails before its closing delimiter instead of
ending as a complete-looking Bundle that does not verify.

Every section is either projected from a named owner or carries a typed
omission in `manifest.statement.section_coverage`:

| Section | Source | Not complete when |
| - | - | - |
| `actors.ndjson`, `work-units.ndjson` | canonical attribution | historical events carry no attribution, or a row budget is reached |
| `interactions.ndjson` | persisted payload coordinates: `tool_use_id`, ActionApproval ids, question ids, observed subagent ids. A tool call pairs only with a result or confirmation from the same Run and subagent (caller input through the Run parked on that `tool_use_id`), so a native id reused across Runs or subagents never crosses executions. An accepted `user.message` is a `message` interaction when the native Session Journal committed its lineage: it is `accepted` while queued and `settled` by the `run.created` that took it, whose thread, actor and work unit are the exact delivery | a coordinate sits in unavailable content; a `user.message` without Journal lineage (older Sessions, ZDR) is counted as a gap rather than inferred from adjacency; a tool result or repeat open the log cannot attribute to exactly one open call is counted as a gap and the call stays `pending` |
| `context-snapshots.ndjson` | platform `session.context_condensed` boundaries: one content-free row each (event id, sequence, `through_sequence`, message counts, digest). No snapshot body is exported | a boundary is out of order or the row budget is reached; a Session that never condensed has zero rows and complete coverage |
| `artifacts/index.ndjson` | model-wire frames named by `wire.call`, Session output Files | output Files bind only to a closed frontier; working-state capture chunks have no persisted manifest yet |
| `continuation-capsules/index.ndjson` | continuation-capsule custody rows inside the frontier | a row budget is reached |

Artifact and capsule bodies are not inside the Bundle. Each index row binds
the exact SHA-256 and byte count and a locator digest for the custody that
holds the bytes (wire frames, Files, capsule vault custody). Fetch them through
their own operations; those reads revalidate the digest and size. An index row
whose class TTL elapsed is typed `unavailable: expired`.

`manifest.statement.source_boundary` says whether the frontier is `closed`: a
terminal `session.status_completed`, `session.status_failed`,
`session.status_canceled`, or a `session.archived` event inside it. An idle
Session is `open`. Session output Files are indexed only for a closed
frontier, because the output index records no sequence that could bind a File
to an open one.

`manifest.statement.signing_identity` is `deployment_pinned` when the
deployment configured `CHECKFU_BUNDLE_PROJECTOR_SIGNING_KEY` and
`CHECKFU_BUNDLE_PROJECTOR_SIGNING_PUBLIC_KEY`, and `ephemeral` otherwise. An
ephemeral signature proves the bytes were not changed after signing; it does
not prove which deployment produced them.

A Bundle is a downstream copy once released. Deleting the Session later does
not recall it. A Bundle export that loses to deletion before release returns
404; one released before deletion fails mid-body when a later page read finds
the Session erased.

## Trajectory export

`POST /v1/sessions/{id}/trajectories/export` selects positions of one
retained Session for a named consumer and returns the selected `sequences`
with a `SessionDataQualityReceipt`. It carries no message rows: read the
content itself through the Session export or the Session Bundle. It needs a
Workspace `root` or `admin` key, and the receipt binds that key as
`exported_by`.

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{ "consumer": "self_improvement", "selector": { "owner_type": "session" } }
```

`consumer` is one of `memory`, `evaluation`, or `self_improvement`. Any other
value, including the retired `sft`, `preference`, and `offline_rl`, is refused
at the request boundary with `400`; it is never mapped to another consumer.
The checks run against one frozen copy of the log, so events appended while
the export runs cannot change it. The receipt marks the selection not
accepted, with every reason, when:

* the Session is still open (`source_not_closed`). It closes on
  `session.archived` or a terminal status at or before the frozen frontier. A
  forked Session copies its source's history, terminal events included, so
  only a closing event after `session.forked` closes it;
* the Session was not created with a learning grant for this consumer
  (`learning_disallowed`, `purpose_not_granted`), or the grant has expired
  (`grant_expired`);
* the Workspace runs zero data retention (`zdr`) or the retention window has
  passed (`retention_expired`);
* a tool call's outcome is unknown (`external_effect_ambiguous`), or
  attribution, causal, or local-sequence coverage is incomplete.

A learning grant is requested at Session creation with
`capture_policy.learning_use: { "disposition": "requested", "purposes": ["self_improvement"], "authorized_until": "..." }`
and is stamped by the creating `root` or `admin` key. A new request may name
`memory_curation`, `evaluation`, and `self_improvement`. A request that names
any other purpose is refused as a whole. Sessions admitted earlier keep the
grant they were admitted with, unchanged. A grant is a record of what was
allowed at admission; it is not renewed, widened, or reused to build a
different export. Retention and learning permission are separate: keeping a
Session does not grant a use, and a grant never extends retention.

Checkfu exports authorized retained Session records for operational use. It
does not produce first-party SFT, preference, offline-RL, or ATIF datasets.
Possession of an export does not grant additional data-use rights or extend
retention. Downstream copies remain the recipient's responsibility: deleting
the Session afterwards does not recall what you already received. An export
requested after deletion returns 404, and so does one whose log read overlaps
the start of a deletion. That check is made once more after the read, not on
every row, so authorize again in your own backend before releasing an export
to an end user.

## Authorization boundary

Export is a read performed under the caller's current API-key and Workspace
scope. An accepted request does not create a durable authorization grant for
future exports or redistribution.

Current evidence does not establish a final authorization and erasure fence
that is re-evaluated across every page of every in-flight export. Therefore,
revoking a key or beginning erasure must not be described as retroactively
invalidating bytes that an already-started stream delivered.

## Deletion and erasure boundary

A new export read can become unavailable after Session deletion or content
erasure. That does not prove that:

* an export already in flight was stopped before it read another page;
* a previously downloaded artifact was disposed of;
* every cache, snapshot, or memory sink was fenced; or
* provider-held copies were erased.

Treat every downloaded export as a new downstream copy under your own
retention policy. Before an erasure workflow, stop new work, revoke relevant
access, cancel or quarantine exports, and retain Audit evidence for each
custody step.

Current implementation and verification do not support a claim that a Session
delete or erasure response alone proves complete disposal across every sink.
See [Retention and zero-data retention](/concepts/retention-and-zdr).

## Sensitive data handling

Exports can contain prompts, responses, tool arguments, observations, and
identity metadata. Store them only in an approved destination, restrict access,
set an explicit retention period, and do not commit real exports to a source
repository.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.