API reference

Browser sync

Cactive Browser's end-to-end encrypted sync of bookmarks, history and settings: the account and its sealed keyset, browsers, requests to add one, and ciphertext records. Every change is signed by the account's sync key.

These routes are at /v1/me/browser-sync, reachable only with Cactive Browser's own sign-in (a browser token): organization keys, Caity and the other apps get 403. Bookmarks, history and settings are encrypted in the browser before they're sent, under a key only your browsers hold, so the server keeps ciphertext, padded sizes and a little metadata (when records changed, which browsers synced).

Signed writes. Reads need only the sign-in. Every request that changes something carries X-Sync-Signature: t=<epoch milliseconds>,d=<device id>,s=<signature>: an Ed25519 signature (base64url) by the sync key over these lines:

cactive-browser-sync/v1/request
<METHOD>
<path>
<t>
<device id>
<base64url SHA-256 of the exact body, or of "" without one>

t must be within 5 minutes of the server's clock (otherwise 403 with code: "clock" and serverTime). Turning sync on is signed with the new sync key itself; a browser that was removed gets 403 with code: "device_removed".

Versions. Every record write names the version it replaces (baseVersion, 0 for a new record); a stale one gets conflict with the current record, and the browser keeps the later change.

Adding a browser. A browser asks to be added (POST /pairings, its one-off public key) and shows a code; a synced browser answers with the keyset sealed for it, mixing in the code the person typed. Or the recovery key opens the keyset sealed under it. The server never sees the code, the recovery key or the keyset.

Resets. POST /reset asks for a reset when no browser and no recovery key can open sync any more: after 7 days, unless a synced browser cancels it, the session alone may purge it. The account's email address is told when sync is turned on, a browser is added and a reset is asked for.

Every route below, with its parameters, request and response, errors and samples, is in the API reference.

RouteWhat it does
GET /v1/me/browser-syncYour sync account (ids, the signing public key, the keyset sealed under your recovery key, a pending reset), the limits and the server's time; account: null when sync is off.
POST /v1/me/browser-syncTurns sync on: the account and this browser, signed by the new sync key. 409 when it's on already.
POST /v1/me/browser-sync/purgeDeletes up to 1,000 of your sync rows a call, the account last (done when nothing is left). Signed by a synced browser, or, 7 days after a reset was asked for, from the session alone.
POST /v1/me/browser-sync/resetAsks for a reset when no browser and no recovery key can open sync any more; a purge may follow after 7 days.
DELETE /v1/me/browser-sync/resetCancels a reset (signed by a synced browser).
GET /v1/me/browser-sync/devicesThe browsers set up for sync, removed ones included.
PUT /v1/me/browser-sync/devices/:deviceIdRegisters (or renames) the signing browser itself.
DELETE /v1/me/browser-sync/devices/:deviceIdRemoves a browser from sync (signed): its changes are refused from then on.
GET /v1/me/browser-sync/pairingsRequests to add a browser that are waiting for an answer.
POST /v1/me/browser-sync/pairingsAsks to add this browser: its one-off public key, name and platform (expires in 10 minutes).
GET /v1/me/browser-sync/pairings/:pairingIdA request and, once a synced browser answered, its answer.
DELETE /v1/me/browser-sync/pairings/:pairingIdWithdraws a request.
POST /v1/me/browser-sync/pairings/:pairingId/approvalA synced browser's answer (signed): its one-off public key and the sealed keyset. Once, before the request expires.
POST /v1/me/browser-sync/recordsUp to 100 changes (signed), each at the version it replaces: ok, conflict with the current record, or refused.
GET /v1/me/browser-sync/recordsA collection's records written since since (ms, less 5 minutes), oldest first, 500 a page (page continues).