Contact

Revisions

Enscrive records revisions of your tenant’s data automatically: a revision every 15 minutes through the current UTC day, and one daily revision for each prior day. A revision is a point-in-time restore point — restoring one returns every corpus in your tenant to its state at that moment.

Three surfaces expose the same capability, all under normal API-key auth (no admin capability required):

  • the Timeline page in the developer portal (/revisions),
  • the /v1 endpoints documented below,
  • the CLI: enscrive revisions list, enscrive revisions show, enscrive restore --revision.

A note on naming. The API paths and field names say backup (/v1/backups, backup_id) — that is the storage-layer vocabulary. The product concept is a revision; the portal, the CLI, and these docs use that word.

What a revision is

Each revision records, for the moment it was taken:

  • the point in time (timestamp),
  • total embedding points and compressed size,
  • per-collection point counts and content checksums,
  • whether the artifact is encrypted, and its parentage in the revision chain,
  • expires_at — when retention will purge it (see Retention by tier).

Revisions are recorded by the platform on a fixed cadence; you do not create them through the API.

The Timeline

The portal’s Timeline page lists every revision recorded for the active tenant, newest first, grouped by UTC day. The two generations are badged distinctly:

  • Today — revisions on a 15-minute cadence.
  • Prior days — one daily revision per day.

Each row expands to the full detail (per-collection points, checksums, parent revision, expiry), and carries the Restore this revision… action, which runs the same preview → typed-confirm → async-job flow described below.

List revisions

GET /v1/backups?limit=20&cursor=…
ParamNotes
limitPage size; the server defaults to 20 when omitted
cursorOpaque pagination cursor — pass the previous page’s next_cursor

Returns backups (an array of revision summaries: backup_id, timestamp, backup_type, total_points, compressed_bytes, encrypted, optional label and expires_at), plus total and next_cursor.

CLI: enscrive revisions list [--limit N] [--cursor C].

Get a revision

GET /v1/backups/{backup_id}

Returns the full detail, including the collections map (point_count + checksum per collection), parent_backup_id, encryption flags, and expires_at.

A revision belonging to another tenant is a 404 — the lookup is keyed by (tenant_id, backup_id) at the source of truth, so a foreign id simply does not resolve. The isolation is structural, not a filter.

CLI: enscrive revisions show <revision-id>.

Verified restore

Restore is tenant-wide and point-in-time: every corpus in the tenant returns to its state as of the named revision’s timestamp. Data added or changed after that moment is not in the restored state. Because of that, the flow has four deliberate stages.

1. Dry-run preview

POST /v1/restore/dry-run
{ "target_time": "2026-06-11T14:45:00Z" }

A synchronous read — nothing is executed. Reports can_restore, backups_in_chain, total_points, estimated_restore_time_seconds, glacier_backups (revisions in cold storage, which restore slower), and warnings. The portal fetches this preview the moment you open the restore dialog; the CLI’s enscrive restore --revision <id> --dry-run resolves the revision’s timestamp and runs the same validation.

2. Typed confirmation

POST /v1/restore
{ "backup_id": "<revision-id>", "confirm": "<revision-id>" }

confirm must repeat the exact revision id. Missing or mismatched → 400, with an error that states the policy: restore is destructive and tenant-wide, and restores never default to the latest revision — you confirm exactly the revision being restored. The portal enforces the same gate by making you type the revision id; the CLI requires --confirm plus an interactive re-type of the id (non-TTY and JSON/agent invocations are refused before any API call; managed mode additionally requires --confirm-token).

3. Always-async launch

A valid request returns 202 Accepted with a job_id and poll_url before any restore work happens — the standard async-mutation contract. Poll it like any other job: the job moves through resolvingrestoringverifying phases, with the row kept visibly alive by a heartbeat while the restore runs.

CLI: enscrive restore --revision <id> --confirm polls to terminal status by default (--timeout-secs, default 1800); pass --async to return immediately with the launched job.

4. Convergence-verified completion

After the restore finishes, the server verifies it per corpus before claiming success: the restored embedding store is compared against the document catalog, corpus by corpus, requiring an exact match in both directions.

  • Every corpus matches → job complete with params.verified: true.
  • Any corpus diverges → job failed, naming the exact shortfall (substrate=X, catalog=Y, corpus=Z). A restore that lands data in a different state than the current catalog is reported as exactly that — never silently stamped complete.
  • The check itself can’t be trusted (stats absent, stale, or unreadable) → job failed as unverifiable. Unknown is never treated as zero and never as converged.

The CLI mirrors this honesty: a restore job that reaches a terminal state without params.verified == true exits non-zero.

Retention by tier

Retention follows a two-generation policy:

  • Current day — revisions every 15 minutes.
  • Day rollover — the last revision of each UTC day becomes that day’s daily revision; the day’s other revisions expire.
  • Dailies window — daily revisions are kept for the most recent days per your subscription tier:
TierDaily revisions kept
Solo7 days
Pro14 days
Enterprise30 days

Two safety properties apply regardless of expiry: the two newest revisions are never purged (a stalled recording cadence must not let the clock destroy the only restorable artifacts), and the windows come from the active rate card — if no retention policy is declared there, nothing is purged.

Every revision’s expires_at is visible on the list and detail endpoints, and on the Timeline.

Erasure

Tenant erasure permanently purges revisions. When a tenant is erased, a tombstone is written first: from that instant no new revisions are recorded and restore/import of that tenant’s data is refused — including via disaster-recovery paths. Then every revision artifact is permanently deleted, both the catalog exports and the embedding-store artifacts. The operation is idempotent, and the tombstone-first ordering means a crash mid-erasure can never leave a window where the erased tenant is restorable.

Cross-references

  • Jobs — polling the tenant_restore job to terminal status.
  • Corpora — what the restored corpora contain.
  • Billing — the rate card that carries the per-tier retention windows.
  • Errors — HTTP-level errors and status codes.