Docs / Reference

API overview

REST for everything, gRPC for the live change feed.

The API is JSON over HTTPS under /api/v1. Authenticate with Authorization: Bearer <device token>. Names, metadata, manifests and values are ciphertext, so the API is most conveniently used through a client library; the Rust core implements all of it.

Sign-in

# 1. fetch the key-derivation parameters (the same shape is returned for unknown users)
curl "https://sync.example.com/api/v1/auth/prelogin?username=alice"

# 2. send the derived login secret (never the password)
curl -X POST https://sync.example.com/api/v1/auth/login \
  -H 'content-type: application/json' \
  -d '{"username":"alice","auth_secret":"…","device_name":"my script"}'
# → { "status": "mfa_required", "token": "<short-lived>", "methods": ["totp","recovery"] }

# 3. prove a second factor
curl -X POST https://sync.example.com/api/v1/auth/mfa/verify \
  -H "authorization: Bearer <short-lived>" -H 'content-type: application/json' \
  -d '{"method":"totp","code":"123456","device_name":"my script"}'
# → { "status": "ok", "token": "<device token>" }

Endpoints

AreaEndpoints
AuthGET /auth/config, GET /auth/prelogin, POST /auth/register, POST /auth/login, POST /auth/mfa/verify, POST /auth/logout
Second factorsGET /me/mfa, PATCH/DELETE /me/mfa/{id}, POST /auth/totp/setup, POST /auth/totp/confirm, POST /auth/webauthn/register/{start,finish}, POST /auth/webauthn/login/{start,finish}, POST /me/recovery-codes
AccountGET /me, POST /me/password, GET /me/devices, DELETE /me/devices/{id}, GET /users/{name}/pubkey
TreeGET /nodes?parent=, POST /nodes, GET/PATCH/DELETE /nodes/{id}, POST /nodes/{id}/restore, DELETE /trash/{id}, GET /shared
VersionsGET/POST /nodes/{id}/versions, GET/DELETE /versions/{id}
ChunksPOST /chunks/missing, PUT/GET /chunks/{hash}
ChangesGET /changes?since=, GET /changes/head
Key/valueGET /kv/{ns}/list, GET/PUT/DELETE /kv/{ns}/e/{key}
SharingPOST/GET /shares, DELETE /shares/{id}, POST/GET /links, DELETE /links/{id}, GET /public/{token}…
AdminGET /admin/users, PATCH/DELETE /admin/users/{id}, POST /admin/users/{id}/reset-2fa, POST /admin/invites, GET/PUT /admin/settings

Optimistic concurrency

Creating a version includes base_version. If it is not the node’s current head the server answers 409 with { "head_version": … }, and the client must merge and retry.

Live changes (gRPC)

service Sync {
  rpc Subscribe(SubscribeRequest) returns (stream Change);
}
message SubscribeRequest { int64 since = 1; }
message Change { int64 cursor = 1; string node_id = 2; string kind = 3; string version_id = 4; string kv_key = 5; }

The same service is available as gRPC-Web for browsers at /syncloom.sync.v1.Sync/Subscribe. Heartbeat messages (cursor 0) are sent every 20 seconds, and the stream ends with an error status if the token is revoked.