The ledger is the source of truth: every holding, reserve, subscription, credential and price is a contract on the parties’ Canton nodes. What you back up beyond your Canton node is what the engine decided and remembers, which nothing on the ledger can give back.

What lives where

The engine’s database

A restore from a backup is almost always the answer to a lost database: every row comes back as it stood. A fresh database is the last resort, for when no backup exists.

Back up

pg_dump takes one consistent snapshot of a live database, so the engine keeps running:
$ENGINE_DB_URL is the postgresql:// form of the engine’s database URL, with a role that reads every table. The dump carries the migration history and the sequences’ positions, which a restore needs.
  • How often you back up sets the loss you accept: everything written after the last backup is lost with the database. For a tighter recovery point, run PostgreSQL with continuous WAL archiving and restore to a point in time instead.
  • Keep the dumps off the database’s host, encrypted: they carry every holder’s party id and your staff’s requests.
  • Test a restore into a scratch database on a schedule. A backup that has never been restored is not known to work.

Restore

1

Stop the engine

Two engines on one database, or an engine on a database being restored, is never safe.
2

Restore into an empty database

3

Start the same or a later engine

It applies any newer migrations as it starts. Never start an older engine on a newer backup: it does not know the newer tables.
4

Resolve what the backup caught unfinished

At start the engine resolves every operation the backup caught queued or running: a settlement whose start is recorded carries on; a distribution whose plan was frozen is confirmed, and one with none fails; anything else fails interrupted, saying what to check before repeating it. Read GET /v1/operations?state=failed and act on each.
5

Check open settlements

Settlements carry on from the ledger. One that settled after the backup still reads open: check each against the ledger, or the feed’s reserve.minted and reserve.redeemed events, before acting on it.
6

Tell the feed's consumers

The feed’s sequence resumes from the backup’s, so events written after the backup are numbered again. A consumer whose cursor is past the newest event, GET /v1/events?order=desc&limit=1, resets to it.
7

Redo what came after the backup

Holders registered, statements posted, mappings changed, holds released: your webhook receivers and your staff’s own records are what remain of them.
The next reconciliation run starts after the restored latest run, so every mint and transfer since the backup is examined. A distribution paid after the backup comes back payable, and its roll finds each line already charged and does not charge it twice.

A fresh database

With no run recorded, reconciliation starts at PQS’s earliest offset. On a fresh database beside a ledger with history, that first run would read every mint and transfer since, with none of the plans, orders or holds that explained them, and stop the book on mints settled long ago. Set the reconciliation start offset (Configuration reference) before the first run, to one of:
  • The last reconciled offset, when you know it: the offset of the last reconciliation.run event a webhook receiver kept, or of the last report exported. Nothing after it goes unexamined.
  • The ledger’s end when the fresh database was created, from GET /v1/system. Mints and transfers between the last run and that offset are never examined: say so in the incident record.
Before setting it, confirm no hold was open when the database was lost, from the last reconciliation.hold and hold.released events: a lifted hold, with a start offset past its finding, is never raised again. The setting applies only while the database has no run, so it can stay set. Related: Audit trail and retention · Upgrades and package versions · Runbooks