Skip to main content

Transactions

Chronicle transactions group related entries under a shared correlation_id.

This gives you workflow-level traceability across multiple audit entries.

Closure API

use Chronicle\Facades\Chronicle;

Chronicle::transaction(function () {
Chronicle::record()
->actor('system')
->action('job.started')
->subject('ledger')
->commit();

Chronicle::record()
->actor('system')
->action('job.finished')
->subject('ledger')
->commit();
});

Entries created inside the closure automatically share a generated correlation id.

Transaction object API

$tx = Chronicle::transaction();

$tx->entry()
->actor('system')
->action('sync.started')
->subject('ledger')
->commit();

$tx->entry()
->actor('system')
->action('sync.finished')
->subject('ledger')
->commit();

$correlationId = $tx->id();

The transaction object gives you explicit access to the correlation id and a builder that is pre-seeded with it.

Manual correlations

You can also set the correlation id directly:

Chronicle::record()
->actor('system')
->action('batch.started')
->subject('ledger')
->correlation('batch-2026-03-10')
->commit();

Nested transactions

Chronicle supports nested transactions and generates hierarchical correlation ids.

If an outer transaction has id:

abc

a nested transaction will look like:

abc.def

That makes workflow tree queries possible through the workflow() scope.

Querying correlated entries

Exact correlation:

$entries = Entry::query()->correlation($tx->id())->get();

Workflow tree:

$entries = Entry::query()->workflow($rootCorrelation)->get();

Important distinction

Chronicle transactions are primarily a correlation feature.

The actual persistence of a single entry still happens inside Chronicle’s own database transaction during commit. Do not treat Chronicle::transaction() as a replacement for Laravel’s broader application transaction semantics.