Skip to contentMenu Download OpenVireo

All of this needs an unlocked Account.

Listing and opening

const vaults = await account.listVaults();
// [{ id, name, role: "read" | "write" | "manage", orgId, currentKeyVersion, pendingKeyVersion, rotationRequired }]

const vault = await account.openVault(vaults[0]!.id);   // downloads and decrypts it
vault.name;
vault.db;        // the kdbxweb database
vault.etag;      // the server version this copy is based on

Names are decrypted on the device. openVault tries the newest key the account holds first and falls back to the previous one, so a vault in the middle of a key rotation still opens.

Reading and writing fields

vault.read("ov://Team/GitHub/password");
vault.read({ groupPath: ["Apps"], entry: "Stripe", field: "username" });

await vault.write("ov://Team/GitHub/password", "new value");                 // edits and syncs
await vault.write("ov://Team/Apps/Stripe/api_key", key, { create: true });  // creates the entry if needed

See Concepts for how references find entries. write keeps the previous version in the entry’s history and stores password and custom fields protected.

Editing the database directly

vault.db is a kdbxweb Kdbx. Change it any way you like, then call sync():

import { addEntryToDb, setItemFields } from "@openvireo/sdk";

const root = vault.db!.getDefaultGroup();
await addEntryToDb(vault.db!, root.uuid.toString(), {
  title: "Database", username: "app", passwordValue: "s3cret", url: "", notes: "", tags: [],
});
setItemFields(vault.db!, { groupPath: ["Apps"], entry: "Api" }, { username: "svc", token: "…" }, { create: true });

const result = await vault.sync();
result.outcome;     // "uploaded", "pulled" (only downloaded), "created" or "unchanged"
result.conflicts;   // entries both sides changed: { uuid, kind, title, fields }
result.changes;     // what the merge did, entry by entry

sync() downloads the server copy, merges it with your changes against the last common version, and uploads the result with If-Match. When another device uploaded in between, it merges again and retries (up to five times, then too_many_conflicts; your changes stay in vault.db). See Merge behaviour.

Call vault.sync({ localChanged: false }) to only pick up changes from elsewhere: it asks the server with a HEAD first and downloads nothing when the version hasn’t moved.

Creating vaults

const personal = await account.createVault("Personal");
const team = await account.createVault("Team Infra", { orgId });   // org owners and admins get manage automatically

createVault makes the vault key, registers the vault with the account server, and uploads an empty database whose root group has the vault’s name. It returns the opened vault.

Sharing

const { principal, fingerprint } = await account.share(vaultId, { email: "[email protected]" }, "write");
await confirmWithBob(fingerprint);   // compare it with what Bob's app shows, out of band

await account.share(vaultId, { principal }, "read");   // changing the role

share looks up the person’s public keys, checks their signature, seals the vault key to them and grants the role. It needs manage on the vault. The other person needs an account already.

Revoking and rotating

await account.revoke(vaultId, [bobPrincipal]);   // removes access and rotates the vault key in one step
await account.rotate(vaultId);                     // a new key without removing anyone

Rotating makes a new vault key, seals it to everyone who stays, re-encrypts the file with it and then makes it current. Access is removed on the server first, so the removed person can’t download the re-encrypted file. Their old downloads still open with the old key, so change the secrets inside if that matters. A vault whose rotationRequired is true (someone left the organisation) should be rotated by a manager.

Organisations

Organisations are managed through the account server API on account.auth, with helpers on Account for the steps that need keys:

const org = await account.auth.createOrg("Acme");
await account.auth.invite(org.id, { email: "[email protected]", role: "member" });
// Carol gets an email, and her app calls account.auth.acceptInvitation(invitationToken)

const { members } = await account.auth.listMembers(org.id);
const carol = members.find((m) => m.email === "[email protected]" && m.status === "accepted")!;
await account.confirmMember(org.id, carol, [{ id: "<vault id>", role: "read" }]);   // seals vault keys to her

await account.setMemberRole(org.id, carol, "admin");   // admins get manage on every org vault
const { rotated, failed } = await account.removeMember(org.id, carol.user_id);   // and rotates her vaults

(await account.auth.me()).orgs lists the organisations the account belongs to.

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