HTTP API: version history
The project's configuration timeline: commits, branches, snapshots, state at a moment, and restoring earlier states.
The project's configuration history over HTTP: what it looked like at any moment, what each change did, and putting things back. Guide: Version history: see, undo and restore changes; SDK: JavaScript: Version history; CLI: CLI: Version history.
| Base URL | https://<project-ref>.sovarias.in — your project URL from Connect. |
| Keys | Send the project's key as apikey. Calls made for a signed-in user also send Authorization: Bearer <access token>. |
| Errors | A status code and {"detail": …} — a sentence, or {code, message} for errors your code may branch on (HTTP API). |
Reading history
GET/api/v1/chrono/state
The project's configuration at any moment: policies, schema, functions, settings, buckets and keys, as files.
Every change to the project is a commit on its timeline (Version history: see, undo and restore changes). Paths look like policies/<id>.spl and policies/<id>.json, schema/<schema>.<table>.json, functions/<name>.json, settings/project.json, storage/<bucket>.json, keys/<key>.json. Up to 2,000 files, each cut at 200 KB.
- Who
- A project team member's session (the console, or a token from
sov login) asAuthorization: Bearer <token>. The member's role must allow the action. - Also at
/v1/chrono/state
Query parameters
timelinestringoptionaldefaultmain- Timeline (default
main). - 0–200 characters
atstring | nulloptional- A commit id (or its start) or an ISO time; now by default.
- 0–64 characters
prefixstringoptional- Only paths under this folder, e.g.
policies/. - 0–200 characters
contentsbooleanoptionaldefaulttruefalselists paths without contents.
Returns
commitstring | null- The commit current at that moment (
nullbefore the first). filesobject- Path → contents (text), or
nullwithcontents=false.
Responses
- 200Success.
- 401No valid session or key.
curl -s "$URL/api/v1/chrono/state?at=2026-10-17T09:00:00Z&prefix=policies/" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN"Response
{
"timeline": "main",
"commit": "9f3c2a71e4b85d06c1a7f2e9",
"timestamp_ns": 1792227600123456789,
"message": "policy pol_orders_read updated",
"files": {
"policies/pol_orders_read.spl": "ALLOW IF ctx.resource.name == \"orders\" AND ctx.actor.is_anonymous == False",
"policies/pol_orders_read.json": "{\"name\": \"Signed-in users read orders\", \"active\": true, \"version\": 3}"
},
"truncated": false
}GET/api/v1/chrono/timelines/{name}/history
A timeline's commits, newest first.
- Who
- A project team member's session (the console, or a token from
sov login) asAuthorization: Bearer <token>. The member's role must allow the action. - Also at
/v1/chrono/timelines/{name}/history
Path parameters
namestringrequired- Timeline (
main).
Query parameters
limitintegeroptionaldefault50- How many.
- 1–500
offsetintegeroptionaldefault0- How many to skip.
- 0–…
Returns
chrononsarray<object>- Commits:
hex_id,short_hex,message,author,timestamp_ns(nanoseconds since 1970),parent_hex_ids,changed_domains(folders touched),event_type,metadata.
Responses
- 200Success.
- 401No valid session or key.
curl -s "$URL/api/v1/chrono/timelines/main/history?limit=20" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN"Response
{
"timeline": "main",
"chronons": [
{
"hex_id": "9f3c2a71e4b85d06c1a7f2e9",
"short_hex": "9f3c2a71e4b8",
"message": "policy pol_orders_read updated",
"author": "ana@acme.com",
"timestamp_ns": 1792227600123456789,
"parent_hex_ids": [
"41aa07d2c96e3b58f0e1d4a2"
],
"changed_domains": [
"policies"
],
"event_type": "policy.updated",
"metadata": {
"policy_id": "pol_orders_read"
}
}
]
}GET/api/v1/chrono/commits/{hex_id}/changes
What one commit changed, item by item, in words — and each item's before and after.
Only the files the commit touched. reference is the commit that made the version this one replaced. With compare_to, compares with that commit instead of the parent. Up to 300 items.
- Who
- A project team member's session (the console, or a token from
sov login) asAuthorization: Bearer <token>. The member's role must allow the action. - Also at
/v1/chrono/commits/{hex_id}/changes
Path parameters
hex_idstringrequired- The commit.
Query parameters
compare_tostring | nulloptional- Another commit to compare with.
- 0–64 characters
Returns
changes[].kindstringpolicy,table,function,settings,bucket,api_key.changes[].changestringadded,removedormodified.changes[].summaryarray<string>- e.g.
column note added (text),allowPublicSignup: false → true,rule changed.
Responses
- 200Success.
- 401No valid session or key.
curl -s "$URL/api/v1/chrono/commits/9f3c2a71e4b85d06c1a7f2e9/changes" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ACCESS_TOKEN"Response
{
"commit": "9f3c2a71e4b85d06c1a7f2e9",
"compared_to": "41aa07d2c96e3b58f0e1d4a2",
"message": "policy pol_orders_read updated",
"author": "ana@acme.com",
"timestamp_ns": 1792227600123456789,
"event_type": "policy.updated",
"metadata": {},
"changes": [
{
"path": "policies/pol_orders_read.spl",
"kind": "policy",
"item": "pol_orders_read",
"change": "modified",
"summary": [
"rule changed"
],
"before": "ALLOW IF ctx.resource.name == \"orders\"",
"after": "ALLOW IF ctx.resource.name == \"orders\" AND ctx.actor.is_anonymous == False",
"reference": {
"hex_id": "77b0…",
"message": "policy pol_orders_read created",
"timestamp_ns": 1791900000000000000,
"author": "ana@acme.com"
}
}
],
"truncated": false
}POST/api/v1/chrono/variance
A line-by-line diff between two commits.
- Who
- A project team member's session (the console, or a token from
sov login) asAuthorization: Bearer <token>. The member's role must allow the action. - Also at
/v1/chrono/variance
Body
old_chronon_hexstringrequired- Older commit.
- pattern `^[0-9a-f]{16,64}
HTTP API: version history | Sovaria Docs new_chronon_hexstringrequired- Newer commit.
- pattern `^[0-9a-f]{16,64}
HTTP API: version history | Sovaria Docs domain_filterstring | nulloptional- Only one folder, e.g.
policies.Returns
hunks[].operationsarray<[string, string]>["+", line]added,["-", line]removed,["=", line]unchanged.
Responses
- 200Success.
- 401No valid session or key.
- 422The body is missing a required field or has a field of the wrong type.
curl -s -X POST "$URL/api/v1/chrono/variance" \ -H "apikey: $ANON_KEY" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{"old_chronon_hex": "41aa07d2c96e3b58f0e1d4a2", "new_chronon_hex": "9f3c2a71e4b85d06c1a7f2e9", "domain_filter": "policies"}'Response
{ "summary": { "insertions": 1, "deletions": 1, "unchanged": 0 }, "hunks": [ { "domain": "policies", "name": "pol_orders_read.spl", "operations": [ [ "-", "ALLOW IF ctx.resource.name == \"orders\"" ], [ "+", "ALLOW IF ctx.resource.name == \"orders\" AND ctx.actor.is_anonymous == False" ] ] } ], "truncated": false, "truncation_reason": null, "processed_hunks": 1, "total_hunks": 1 }GET
/api/v1/chrono/timelines/topologyCommits and their parent links, to draw the history graph.
- Who
- A project team member's session (the console, or a token from
sov login) asAuthorization: Bearer <token>. The member's role must allow the action. - Also at
/v1/chrono/timelines/topology
Query parameters
timelinestringoptionaldefaultmain- Timeline.
limitintegeroptionaldefault50- How many commits.
- 1–500
Returns
nodesarray<object>required3 fields
chronon_hexstringrequiredmessagestringrequiredparentsarray<string>required
edgesarray<object>required2 fields
from_nodestringrequiredto_nodestringrequired
Responses
- 200Success.
- 401No valid session or key.
curl -s "$URL/api/v1/chrono/timelines/topology?timeline=main&limit=50" \ -H "apikey: $ANON_KEY" \ -H "Authorization: Bearer $ACCESS_TOKEN"Response
{ "nodes": [ { "chronon_hex": "9f3c2a71e4b85d06c1a7f2e9", "message": "policy pol_orders_read updated", "parents": [ "41aa07d2c96e3b58f0e1d4a2" ] } ], "edges": [ { "from_node": "41aa07d2c96e3b58f0e1d4a2", "to_node": "9f3c2a71e4b85d06c1a7f2e9" } ] }Undo and restore
Always a plan first, then the same call with
confirm: true.POST
/api/v1/chrono/commits/{hex_id}/undo-planWhat undoing one commit would do — nothing is changed.
Each file the commit changed gets an action that puts it back; a schema commit is undone by rolling migrations back to just before it (
schema_previewis that dry run).changed_sinceflags files changed again after the commit. Policy actions come with a preview of who gains or loses access.- Who
- A project team member's session (the console, or a token from
sov login) asAuthorization: Bearer <token>. The member's role must allow the action. - Also at
/v1/chrono/commits/{hex_id}/undo-plan
Path parameters
hex_idstringrequired- The commit.
Responses
- 200Success.
- 401No valid session or key.
curl -s -X POST "$URL/api/v1/chrono/commits/9f3c2a71e4b85d06c1a7f2e9/undo-plan" \ -H "apikey: $ANON_KEY" \ -H "Authorization: Bearer $ACCESS_TOKEN"Response
{ "commit": "9f3c2a71e4b85d06c1a7f2e9", "parent": "41aa07d2c96e3b58f0e1d4a2", "migration_versions": [], "actions": [ { "type": "policy.restore", "path": "policies/pol_orders_read.spl", "policy_id": "pol_orders_read", "name": "Signed-in users read orders", "spl_source": "ALLOW IF ctx.resource.name == \"orders\"", "exists_now": true, "changed_since": false } ], "automated": 1, "manual": 0, "changed_since": 0, "preview": { "violations": [], "changes": [ { "persona": "__guest__", "who": "Visitors who aren't signed in", "action": "sql:select", "resource": "orders", "before": "DENY", "after": "ALLOW" } ] }, "schema_preview": null }POST
/api/v1/chrono/commits/{hex_id}/undoUndo one commit (after reviewing its plan).
Applied through the public API with your own token, so every permission check, plan limit and audit entry applies; the undo shows on the timeline as new commits.
manualactions are listed for you to do.- Who
- A project team member's session (the console, or a token from
sov login) asAuthorization: Bearer <token>. The member's role must allow the action. - Also at
/v1/chrono/commits/{hex_id}/undo
Path parameters
hex_idstringrequired- The commit.
Body
confirmbooleanoptionaldefaultfalse- Must be
true.
Responses
- 200Success.
- 400Send
confirm: trueafter reviewing the undo plan. - 401Sign in to undo.
- 422The body is missing a required field or has a field of the wrong type.
curl -s -X POST "$URL/api/v1/chrono/commits/9f3c2a71e4b85d06c1a7f2e9/undo" \ -H "apikey: $ANON_KEY" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{"confirm": true}'Response
{ "commit": "9f3c2a71e4b85d06c1a7f2e9", "parent": "41aa07d2c96e3b58f0e1d4a2", "migration_versions": [], "results": [ { "type": "policy.restore", "path": "policies/pol_orders_read.spl", "status": "applied", "http_status": 200, "detail": null } ], "applied": 1, "failed": 0, "manual": 0 }POST
/api/v1/chrono/restore-planWhat going back to an earlier moment would change — nothing is changed.
One action per file that differs between then and now:
policy.restore/policy.remove,settings.restore,function.rollback(to the version active then),bucket.restore/bucket.recreate(settings only, not files), and*.manualfor what isn't automated (schema changes need a migration or a database restore; API keys are re-issued, never revived). Withinclude_database,databaseis the closest backup before that moment (Backups and recovery).- Who
- A project team member's session (the console, or a token from
sov login) asAuthorization: Bearer <token>. The member's role must allow the action. - Also at
/v1/chrono/restore-plan
Body
atstringrequired- A commit id or an ISO time.
timelinestringoptionaldefaultmainonlyarray<string>optional- Only paths starting with these, e.g.
["policies/"]. include_databasebooleanoptionaldefaultfalse- Also plan the database restore.
confirmbooleanoptional- Ignored here.
Responses
- 200Success.
- 401No valid session or key.
curl -s -X POST "$URL/api/v1/chrono/restore-plan" \ -H "apikey: $ANON_KEY" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{"at": "2026-10-17T09:00:00Z", "only": ["policies/", "settings/"]}'Response
{ "at": "41aa07d2c96e3b58f0e1d4a2", "actions": [ { "type": "policy.restore", "path": "policies/pol_orders_read.spl", "policy_id": "pol_orders_read", "name": "Signed-in users read orders", "spl_source": "ALLOW IF ctx.resource.name == \"orders\"", "exists_now": true }, { "type": "settings.restore", "path": "settings/project.json", "settings": { "allowPublicSignup": false } } ], "automated": 2, "manual": 0, "database": null, "preview": { "violations": [], "changes": [] } }POST
/api/v1/chrono/restoreGo back to an earlier moment: applies the plan's automated actions.
Review
restore-planfirst; nothing happens withoutconfirm: true. The database is restored only withinclude_database: true(after a safety backup). Results per action:applied,failed,manualorskipped.- Who
- A project team member's session (the console, or a token from
sov login) asAuthorization: Bearer <token>. The member's role must allow the action. - Also at
/v1/chrono/restore
Body
atstringrequired- Commit id or ISO time.
- 4–64 characters
timelinestringoptionaldefaultmain- Timeline.
- 0–200 characters
confirmbooleanoptionaldefaultfalse- Must be
true. onlyarray<string>optional- Path prefixes.
- 0–50 items
include_databasebooleanoptionaldefaultfalse- Also restore the database from the closest backup before then.
Responses
- 200Success.
- 401No valid session or key.
- 422The body is missing a required field or has a field of the wrong type.
curl -s -X POST "$URL/api/v1/chrono/restore" \ -H "apikey: $ANON_KEY" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{"at": "2026-10-17T09:00:00Z", "confirm": true, "only": ["policies/"]}'Response
{ "at": "41aa07d2c96e3b58f0e1d4a2", "results": [ { "type": "policy.restore", "path": "policies/pol_orders_read.spl", "status": "applied", "http_status": 200, "detail": null } ], "applied": 1, "failed": 0, "manual": 0 }Timelines and commits
GET
/api/v1/chrono/timelinesThe project's timelines.
- Who
- A project team member's session (the console, or a token from
sov login) asAuthorization: Bearer <token>. The member's role must allow the action. - Also at
/v1/chrono/timelines
Returns
timelinesarray<object>required3 fields
namestringrequiredhead_hexstringrequiredchronon_countintegeroptionaldefault0
Responses
- 200Success.
- 401No valid session or key.
curl -s "$URL/api/v1/chrono/timelines" \ -H "apikey: $ANON_KEY" \ -H "Authorization: Bearer $ACCESS_TOKEN"Response
{ "timelines": [ { "name": "main", "head_hex": "9f3c2a71e4b85d06c1a7f2e9", "chronon_count": 412 }, { "name": "try-new-rules", "head_hex": "c0de…", "chronon_count": 3 } ] }POST
/api/v1/chrono/timelines/spawnStart a new timeline (a branch) from a commit.
- Who
- A project team member's session (the console, or a token from
sov login) asAuthorization: Bearer <token>. The member's role must allow the action. - Also at
/v1/chrono/timelines/spawn
Body
namestringrequired- Letters, digits,
._-(up to 64). - pattern `^[A-Za-z0-9][A-Za-z0-9._-]{0,63}
HTTP API: version history | Sovaria Docs source_hex_idstring | nulloptional- The commit to start from (default: the head of
main).- pattern `^[0-9a-f]{16,64}
HTTP API: version history | Sovaria Docs Returns
timelinestringrequiredspawned_from_hexstringrequiredcreated_at_nsintegerrequired
Responses
- 201Created.
- 401No valid session or key.
- 422The body is missing a required field or has a field of the wrong type.
curl -s -X POST "$URL/api/v1/chrono/timelines/spawn" \ -H "apikey: $ANON_KEY" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{"name": "try-new-rules", "source_hex_id": "9f3c2a71e4b85d06c1a7f2e9"}'Response
{ "timeline": "try-new-rules", "spawned_from_hex": "9f3c2a71e4b85d06c1a7f2e9", "created_at_ns": 1792310000000000000 }POST
/api/v1/chrono/timelines/{name}/jumpMove a timeline's head to another commit (a history rewind of the record, not of the project).
For timelines other than
main—mainonly moves forward (409); to go back, use restore. Uses one rollback from the plan's monthly allowance (chrono.rollbacks_month).- Who
- A project owner or admin.
- Also at
/v1/chrono/timelines/{name}/jump
Path parameters
namestringrequired- Timeline.
Body
target_hexstringrequired- The commit.
- pattern `^[0-9a-f]{16,64}
HTTP API: version history | Sovaria Docs jumpedbooleanrequiredprevious_headstringrequirednew_headstringrequired- 200Success.
- 409
main only moves forward: use restore to go back. - 403Not an owner/admin, or
PLAN_QUOTA_EXHAUSTED. - 401No valid session or key.
- 422The body is missing a required field or has a field of the wrong type.
- Who
- A project owner or admin.
- Also at
/v1/chrono/timelines/convergetargetstringrequired- Timeline to merge into.
sourcestringrequired- Timeline to merge from.
authorstringrequired- Who.
messagestring | nulloptional- Commit message.
strategystring- One of
FAST_FORWARD,THREE_WAY_MERGE - 200Success.
- 401No valid session or key.
- 422The body is missing a required field or has a field of the wrong type.
- Who
- A project owner or admin.
- Also at
/v1/chrono/timelines/{name}namestringrequired- Timeline.
deletedbooleanrequiredtimelinestringrequired- 200Success.
- 400
maincan't be deleted. - 401No valid session or key.
- Who
- A project team member's session (the console, or a token from
sov login) asAuthorization: Bearer <token>. The member's role must allow the action. - Also at
/v1/chrono/committimelinestringoptionaldefaultmainmessagestringrequired- 1–2000 characters
authorstringoptionaldefaultsystemevent_typestringoptionalmetadataobjectoptionalmutationsarray<object>optional5 fields
domainstringrequired- Capitals, digits,
._-. namestringrequiredoperationstringoptional- One of
upsert,delete payload_textstringoptional- Text contents (or
payload_json, not both; neither for delete). payload_jsonobject | arrayoptional
hex_idstringrequiredtimelinestringrequiredtimestamp_nsintegerrequired- 201Created.
- 401No valid session or key.
- Who
- A project team member's session (the console, or a token from
sov login) asAuthorization: Bearer <token>. The member's role must allow the action. - Also at
/v1/chrono/snapshotssnapshotsarray<object>required8 fields
snapshot_idintegerrequiredmessagestringrequiredcreated_at_nsintegerrequiredbase_chronon_hexstringrequiredproject_idstringoptional- The project id.
authorstringoptionaldegradedbooleanoptionaldefaultfalseengine_countintegeroptionaldefault0
- 200Success.
- 401No valid session or key.
- Who
- A project team member's session (the console, or a token from
sov login) asAuthorization: Bearer <token>. The member's role must allow the action. - Also at
/v1/chrono/snapshots/createmessagestringrequired- A label.
degradedboolean- Some service didn't answer; restoring it will be partial.
- 201Created.
- 401No valid session or key.
- 422The body is missing a required field or has a field of the wrong type.
- Who
- A project owner or admin.
- Also at
/v1/chrono/snapshots/{snapshot_id}/restoresnapshot_idintegerrequired- The snapshot.
restore_statusstringfull,partialordegraded(some services didn't confirm).- 200Success.
- 403Not an owner/admin, or
PLAN_QUOTA_EXHAUSTED. - 404No such snapshot in this project.
- 401No valid session or key.
Returns
Responses
curl -s -X POST "$URL/api/v1/chrono/timelines/try-new-rules/jump" \ -H "apikey: $ANON_KEY" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{"target_hex": "41aa07d2c96e3b58f0e1d4a2"}'Response
{ "jumped": true, "previous_head": "9f3c2a71e4b85d06c1a7f2e9", "new_head": "41aa07d2c96e3b58f0e1d4a2" }POST
/api/v1/chrono/timelines/convergeMerge one timeline into another.
Body
Returns
Responses
curl -s -X POST "$URL/api/v1/chrono/timelines/converge" \ -H "apikey: $ANON_KEY" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{"target": "main", "source": "try-new-rules", "author": "ana@acme.com", "message": "Adopt new rules"}'Response
{ "strategy": "THREE_WAY_MERGE", "new_head_hex": "e5f1…", "conflict_count": 0 }DELETE
/api/v1/chrono/timelines/{name}Delete a timeline (not
main).Path parameters
Returns
Responses
curl -s -X DELETE "$URL/api/v1/chrono/timelines/try-new-rules" \ -H "apikey: $ANON_KEY" \ -H "Authorization: Bearer $ACCESS_TOKEN"Response
{ "deleted": true, "timeline": "try-new-rules" }POST
/api/v1/chrono/commitRecord your own commit on a timeline (for example a release note, or a file of your own).
Sovaria records its own commits automatically; use this to add yours.
domainis a folder in capitals (RELEASES),namethe file in it.Body
Returns
Responses
curl -s -X POST "$URL/api/v1/chrono/commit" \ -H "apikey: $ANON_KEY" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{"message": "Release 2.4.0", "author": "ci@acme.com", "event_type": "release", "mutations": [{"domain": "RELEASES", "name": "2.4.0.json", "payload_json": {"version": "2.4.0", "git_sha": "a1b2c3d"}}]}'Response
{ "hex_id": "9f3c2a71e4b85d06c1a7f2e9", "timeline": "main", "timestamp_ns": 1792310000000000000 }Snapshots
GET
/api/v1/chrono/snapshotsNamed snapshots of the project.
Returns
Responses
curl -s "$URL/api/v1/chrono/snapshots" \ -H "apikey: $ANON_KEY" \ -H "Authorization: Bearer $ACCESS_TOKEN"Response
{ "snapshots": [ { "snapshot_id": 12, "message": "before launch", "created_at_ns": 1792310000000000000, "base_chronon_hex": "9f3c2a71e4b85d06c1a7f2e9", "project_id": "f0c3e9a2-…", "author": "ana@acme.com", "degraded": false, "engine_count": 6 } ] }POST
/api/v1/chrono/snapshots/createTake a named snapshot: the current commit plus each service's position, to restore together.
Body
Returns
Responses
curl -s -X POST "$URL/api/v1/chrono/snapshots/create" \ -H "apikey: $ANON_KEY" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{"message": "before launch"}'Response
{ "snapshot_id": 12, "base_chronon_hex": "9f3c2a71e4b85d06c1a7f2e9", "lock_time_us": 1840, "engine_pointers": { "guard": 412, "forge": 98 }, "created_at_ns": 1792310000000000000, "degraded": false }POST
/api/v1/chrono/snapshots/{snapshot_id}/restoreRestore a snapshot.
Uses one rollback from the plan's monthly allowance (
chrono.rollbacks_month).Path parameters
Returns
Responses
curl -s -X POST "$URL/api/v1/chrono/snapshots/12/restore" \ -H "apikey: $ANON_KEY" \ -H "Authorization: Bearer $ACCESS_TOKEN"Response
{ "restored": true, "snapshot_id": 12, "total_time_ms": 940, "engines_acked": [ "guard", "forge" ], "engines_requested": [ "guard", "forge" ], "restore_status": "full", "degraded": false }Something unclear or missing on this page?Tell us