VESvault REST API
The VESvault REST API at https://api.ves.host/v1/ stores and shares encryption keys. It is the API that libVES.js, libVES.c and the ves utility call.
All encryption happens in the client. The API stores public keys, encrypted private keys and encrypted values, and never receives a private key or a Vault Item value in the clear. A client that writes keys or values has to do that encryption itself, exactly as libVES does – so for anything that creates, unlocks or shares keys, use libVES.
This page describes the request and response format, the objects, and the parts of the API that are useful on their own: reading objects, paging through lists and watching for changes. Errors are listed in VESvault API Error Numbers.
Requests
https://api.ves.host/v1/ Base URL All requests.
https://poll.ves.host/v1/ Base URL The same API, for requests that wait for changes.
The path is a collection, optionally followed by an object ID: vaultKeys/654321. The collections are users, vaultKeys, vaultItems, files, externals, domains, events and sessions, plus:
me User The user of the current session.
attn Object vaultKeys that need the user's action, such as a temp key to rekey or a recovery in progress.
logout   Ends the current session.
GET Method Read an object.
POST Method Find, create or change objects. The body is JSON – see Writing.
PUT Method Update the object in the path.
DELETE Method Delete the object in the path.
Query parameters: fields (Selecting Fields), limit (Lists and Ranges) and poll (Watching for Changes). Send Accept: application/json, and Content-Type: application/json with a body. The API accepts cross-origin requests, so a web page can call it directly.
GET https://api.ves.host/v1/me?fields=id,email,currentVaultKey(id,type,algo)
Authorization: Bearer session-token
Responses
Every response is a JSON object. The requested object is in result:
{
    "result": {
        "id": 123456,
        "email": "alice@example.com",
        "firstName": "Alice",
        "lastName": "Example",
        "currentVaultKey": {
            "id": 654321,
            "type": "current",
            "algo": "ECDH"
        }
    }
}
result Object The object, with the fields the session may read.
errors Array Present when something failed. The HTTP status comes from the first entry. See VESvault API Error Numbers.
ranges Array Present when the request used a range. See Lists and Ranges.
  • IDs are positive integers, sent as JSON numbers.
  • Dates are UTC, ISO 8601, with an optional fraction of a second: 2026-11-02T14:05:09Z.
  • A response can include fields that were not asked for. Ignore them.
  • The X-VES-Server response header names the server version. Include it when you report a problem.
A field the session is not allowed to read is left out of the result, exactly like a field with no value. An absent field can mean either. An empty list ([]) means the list is readable and has no entries.
Authentication
A request carries a session token in the Authorization header:
Authorization: Bearer session-token
Session tokens come from libVES. When an app unlocks a vault with libVES.js or libVES.c, the library obtains a session token and sends it with every call. The server issues each token encrypted to a Vault Key, so only a client that can unlock that key can use it.
  • A token stops working when it expires or after logout. Errors 3014 and 3015 mean the vault has to be unlocked again.
  • A Bearer value that starts with ~ is a verify token: read-only access to one Vault Item or File, given to a third party to prove access. See VESauth.
  • A request with no Authorization header runs without a session and sees only public data, such as the active Vault Keys a user can be shared with.
  • HTTP Basic authorization is part of the VESvault sign-in flow and is not covered here.
Objects
Each object is listed with its path and its main fields. Objects have other fields, used by libVES. Which fields a session can read depends on how it relates to the object.
User (users/id, me)
A VESvault account. me is the user of the current session.
id Integer The user ID.
email String The account email address.
firstName String  
lastName String  
currentVaultKey Vault Key The Primary Vault Key, type current.
shadowVaultKey Vault Key The VESrecovery key, type shadow.
activeVaultKeys Array(Vault Key) The keys others share with: the current and shadow keys.
vaultKeys Array(Vault Key) Every key of the account, including secondary and deleted keys.
events Array(Event) The account's event log.
createdAt Date  
updatedAt Date  
Vault Key (vaultKeys/id)
A key pair. The public key is stored as is; the private key only in encrypted form.
id Integer The Vault Key ID.
type String One of the key types.
algo String The key algorithm: ECDH, RSA or OQS (post-quantum).
publicKey String The public key, PEM.
privateKey String The private key, encrypted on the client with the key's passphrase (its VESkey) before it was sent.
user User The owner.
creator User For a temp key, the user who created it.
externals Array(External) For a secondary key, the app domain and external ID that name the vault.
vaultEntries Array(Vault Entry) One entry for every Vault Item shared with this key.
vaultItems Array(Vault Item) Items that belong to the key itself, such as a temp key's passphrase or recovery tokens. Items shared with the key are under vaultEntries.
events Array(Event) The key's event log.
createdAt Date  
updatedAt Date  
Key types:
current   The Primary Vault Key. One per account; its passphrase is the user's primary VESkey.
shadow   The key VESrecovery restores access with. One per account.
recovery   A shadow key whose recovery is in progress.
secondary   An App Vault key, named by an External. Its VESkey is kept as a Vault Item in the owner's Primary Vault.
temp   A key created by another user for someone who has no suitable key yet, so that items can be shared with them. Rekeyed later and deleted.
lost   A former current key whose VESkey the user has lost.
pending   Reserved for background operations.
deleted   A deleted key.
Vault Item (vaultItems/id)
A secret value, such as a file encryption key or a password, shared with one or more Vault Keys. An item belongs either to a File or to a Vault Key.
id Integer The Vault Item ID.
type String string, file, password or secret.
file File The File the item belongs to.
vaultKey Vault Key The Vault Key the item belongs to.
vaultEntries Array(Vault Entry) One entry for every Vault Key the item is shared with.
meta Object Application metadata, any JSON. Stored unencrypted – never put secrets here.
deleted Boolean The item has been deleted.
verifyToken String A token that proves access to this item to a third party. See VESauth.
events Array(Event) The item's event log.
createdAt Date  
updatedAt Date  
Vault Entry (no path of its own)
One Vault Item shared with one Vault Key. Reached through vaultEntries on an item or a key.
id Integer The Vault Entry ID.
vaultItem Vault Item  
vaultKey Vault Key  
encData String The item's value, encrypted to this key's public key. Base64.
File (files/id)
A named object in an app domain, addressed as //domain/externalId. Its Vault Item holds the secret for it, such as a file's encryption key.
id Integer The File ID.
externals Array(External) The domain and external ID that name the file.
vaultItem Vault Item The item holding the secret.
name String An optional file name.
path String An optional path.
creator User The user who created the file.
verifyToken String As on a Vault Item.
External (externals/id)
A name in an app domain: the domain, externalId pair that addresses an App Vault or a File.
id Integer The External ID.
domain Domain  
externalId String The name within the domain.
vaultKey Array(Vault Key) The App Vault key the name points to.
Domain (domains/id, domains/name)
An app domain. Visible to the domain's own sessions and to its creator.
id Integer The Domain ID.
name String  
description String  
url String  
tags Array The names the domain is known by.
creator User  
vaultKeys Array(Vault Key) The App Vault keys in the domain.
vaultItems Array(Vault Item) The items in the domain.
externals Array(External) The names in the domain.
events Array(Event) The domain's event log.
createdAt Date  
updatedAt Date  
Event (events/id)
One entry in an event log.
id Integer The Event ID. Event IDs increase over time.
type String One of the event types.
recordedAt Date  
user User The user the event is about.
creator User  
vaultKey Vault Key The key the event is about, where there is one.
vaultItem Vault Item The item the event is about, where there is one.
vaultEntry Vault Entry For vaultEntry.* events.
session Session For session.* events.
authorSession Session The session that made the change.
Event types: user.created, user.updated, user.pending, vaultKey.created, vaultKey.deleted, vaultKey.lost, vaultKey.listening, vaultKey.pending, vaultItem.created, vaultItem.updated, vaultItem.deleted, vaultItem.listening, vaultEntry.created, vaultEntry.deleted, session.created, session.updated. More types may be added.
Session (sessions/id)
A session opened with a session token.
id Integer The Session ID.
user User  
vaultKey Vault Key The key the session was opened with, where there is one.
domain Domain  
createdAt Date  
expiresAt Date  
accessAt Date The last time the session was used, approximately.
remote String The client's IP address.
userAgent String The client's User-Agent.
Selecting Fields
The fields parameter names the fields to return. Names are separated by commas. The fields of a related object or a list go in parentheses after its name:
GET https://api.ves.host/v1/vaultItems/777?fields=id,type,meta,vaultEntries(vaultKey(id,type,user(email)))
  • A name the object does not have is ignored, without an error. If a field is missing, check its spelling.
  • Nesting is limited to 8 levels, counting the requested object (2071).
  • Without fields, the response holds a few identifying fields only.
  • Encode + as %2B in a range – an unencoded + in a URL reads as a space. libVES also encodes [ and ] as %5B and %5D.
Lists and Ranges
Lists are returned in ID order. A list without a range is returned whole, up to a limit set by the server; a longer list answers 9011 (HTTP 507) with the first part of the list. The limit parameter lowers that limit for one request.
To read a list in pages, put a range after it in fields: [start+count], as in events(id,type)[0+100]. start is an object ID, not a position: the list returns up to count objects whose ID is start or higher, and 0 starts from the beginning. [start-count] goes the other way, from start down ([0-100] is the 100 highest IDs).
The response carries one ranges entry for each ranged list:
"ranges": [
    { "path": ["events"], "returned": 100, "more": true, "nextId": 18234 }
]
path Array The list, as field names from the requested object.
returned Integer How many entries this page holds.
more Boolean The page is full, so there may be more. false means the list has ended.
nextId Integer The start for the next page, in the same direction.
Watching for Changes
Users, Vault Keys, Vault Items and Domains have event logs (events). To wait for new events, ask for the events from the next ID you expect, and add poll:
GET https://poll.ves.host/v1/vaultKeys/654321?fields=events(id,type,recordedAt)%5B18234%2B100%5D&poll=60
If there are events from that ID on, the API returns them at once. If not, it holds the request for up to poll seconds (at most 120), returns soon after an event is recorded, or returns an empty list when the time runs out. Then ask again from nextId. A Domain's vaultItems and externals lists can be watched the same way. libVES.js does this for you.
Writing
A POST sends one object as JSON. Each key is a field; related objects and lists nest inside it. The response is the resulting object, read back with fields. $op on any object in the body says what to do with that object:
fetch $op Find an existing object by the fields given, and change nothing. An error if there is none.
match $op Like fetch, and the given fields must equal the stored ones.
create $op Create the object. An error if it exists.
update $op Change an existing object.
delete $op Delete the object. On a Vault Entry inside a Vault Item, stop sharing the item with that key.
ignore $op Refer to the object without changing it.
Without $op, the API finds the object if it exists, creates it if not, and saves the fields that changed. "$ref": "#/path" stands for an object already given elsewhere in the same body. For example, to look up an App Vault key by its name:
POST https://api.ves.host/v1/vaultKeys?fields=id,type,algo,publicKey

{ "$op": "fetch", "externals": [ { "domain": "demo", "externalId": "alice" } ] }
The API checks each change against the session's permissions and the state of the objects, and rejects an invalid one with the error numbers in VESvault API Error Numbers. It cannot check the encrypted values themselves, which is why writes that carry keys or encrypted data are left to libVES.
Deleting a Vault Item or a Vault Key marks it as deleted. Accounts are not deleted through the API.
Limits
  • Nesting: 8 levels of fields (2071).
  • Size: a list longer than the server's limit, or a response too large to build, answers HTTP 507 (9xxx). Ask for fewer fields or use a range.
  • Quota: each request is charged against several budgets. When one runs out the API answers HTTP 503 (8xxx). Retry later, with an increasing delay.
What the Server Stores
Readable by the server: account email addresses and names; public keys, key types and algorithms; domain names and external IDs; Vault Item types and meta; file names and paths; the event logs; and session records with their times, the client's IP address and User-Agent.
Encrypted on the client: Vault Item values, held as one Vault Entry per Vault Key, each encrypted to that key; and private keys, encrypted with the key's passphrase. VESkeys and private keys reach the server only in encrypted form.
Not stored: file contents. VESvault holds the key to a file, not the file.
Stability
  • Paths under /v1/ are stable.
  • New fields, event types and error numbers may be added. Existing fields are not removed.
  • Error numbers keep their meaning. Match on number or code, never on the message.