Skip to contentMenu Download OpenVireo

Without an account, the SDK syncs ordinary password-protected .kdbx files with a self-hosted OpenVireo Sync Server, the same way the desktop app does. There are no vaults, no sharing and no keys beyond the database’s own password: each database is one file under the user’s name on the server.

Pairing

A device gets a token of its own by claiming a pairing code from another device (Pair Device… in the desktop app) or from the server (openvireo-sync-server devices pair alice):

import { SelfHostedSync } from "@openvireo/sdk";

const server = await SelfHostedSync.pair("https://sync.example.org", "ABCD-EFGH", "Web", { storage });

// next time
const again = await SelfHostedSync.restore("https://sync.example.org", { storage });

The token is kept in storage. Calling a server from a web app needs the server to allow the app’s origin (SYNC_ALLOWED_ORIGINS, see the sync server’s CORS section).

Syncing a database

import { decryptKdbx, passwordCredentials } from "@openvireo/sdk";

const { dbInstance } = await decryptKdbx(fileBytes, password);
const result = await server.syncDatabase("personal", {
  db: dbInstance,
  credentials: passwordCredentials(password),
});
// result.db is the merged copy: save it locally and keep working on it

The first sync of a database id uploads it. Later syncs download the server copy, merge it with yours against the last common version, and upload the result, retrying on conflicts. The sync state (ETag, revision, base copy) is kept in storage under the database id; without storage, pass it yourself as state and keep result.state.

If another device changed the database’s password, the server copy doesn’t open with yours (vault_key_mismatch): ask for the other password and pass both, newest first, as credentials: [passwordCredentials(newPassword), passwordCredentials(password)].

Other calls

const databases = await server.listDatabases();          // [{ id, revision, etag, size, updatedAt }]
const { code } = await server.createPairingCode();       // for the next device
const stream = server.events({ onEvent: (e) => e.type === "database" && resync(e.id) });

server.client is the underlying SyncClient, with every database route (history, delete, conditional requests).

The SDK docs cover OpenVireo SDK, develop (86e6cd2), last updated 26 October 2026. Found a mistake? Edit this page on GitHub.