API reference

Passwords vault

The Authenticator app's encrypted vault: the account and its sealed keys, vaults, items, devices and resets. The server stores ciphertext; every change is signed by the vault's own key.

See Passwords. These routes are at /v1/me/vault, reachable only with the Authenticator app's own sign-in (a mobile token issued to the authenticator app): organization keys, Caity and the other apps get 403. Item contents and vault names are encrypted on the phone before they're sent, so the server holds ciphertext, padded sizes and a little metadata (when things changed, which devices synced).

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

cactive-vault/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). Making a vault is signed with the new vault's own key; a device that was removed gets 403 with code: "device_removed".

Revisions. Every write names the revision it replaces; a stale one gets 409, and the app merges field by field and tries again.

Resets. An unsigned DELETE asks for a reset: after 7 days, unless a device that can open the vault cancels it, the vault can be deleted and made again. The account's email address is told when a reset is asked for. A signed DELETE deletes the vault at once.

GET /v1/me/vault

Your Passwords vault as stored: account (the keyset sealed under your master password and Secret Key, the Argon2id settings and salt, the public keys) or null, vaults with their wrapped keys and counters, devices, a pending reset and limits. Everything that says what's in the vault is encrypted on your devices. From the Authenticator app's sign-in only.

Auth: user access token or platform agent key

Response 200

{
  account: null | {
    createdAt: number
    updatedAt: number
    accountId: string
    kdfSalt: string
    keyset: string
    keysetRevision: number
    encryptionPublicKey: string
    signingPublicKey: string
    kdf: {
      alg: "argon2id"
      m: number
      t: number
      p: number
    }
  }
  vaults: {
    vaultId: string
    kind: "personal"
    role: "owner"
    envelope: string
    attrs: string
    attrsRevision: number
    revision: number
    itemCount: number
    createdAt: number
    updatedAt: number
  }[]
  devices: {
    deviceId: string
    name: string
    platform: string
    createdAt: number
    lastSeenAt: number
  }[]
  reset: null | {
    requestedAt: number
    at: number
  }
  limits: {
    maxItems: number
    maxDevices: 20
  }
}

Errors

StatusMessage
403Passwords opens only in the Authenticator app.

POST /v1/me/vault

Makes your vault: the account, a personal vault and the first device, all sealed on the device and signed with the new vault's own key (X-Vault-Signature). 409 (exists) when you have one, unless its reset is due, when the old vault is deleted first.

Auth: user access token or platform agent key

Request body (up to 16 KB)

FieldTypeRequiredNotes
accountIdstringYes
kdfobjectYes
kdf.alg"argon2id"Yes
kdf.mintegerYes
kdf.tintegerYes
kdf.pintegerYes
kdfSaltstringYesmatches ^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$
keysetany JSONYes
encryptionPublicKeystringYesmatches ^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$
signingPublicKeystringYesmatches ^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$
vaultobjectYes
vault.vaultIdstringYesmatches ^[A-Za-z0-9_-]{22}$
vault.envelopeany JSONYes
vault.attrsany JSONYes
deviceobjectYes
device.deviceIdstringYesmatches ^[A-Za-z0-9_-]{22}$
device.namestringYes1–80 characters; trimmed
device.platform"ios" | "android" | "web"Yes

Also checked: Unknown fields are rejected.

Response 201

{
  account: null | {
    createdAt: number
    updatedAt: number
    accountId: string
    kdfSalt: string
    keyset: string
    keysetRevision: number
    encryptionPublicKey: string
    signingPublicKey: string
    kdf: {
      alg: "argon2id"
      m: number
      t: number
      p: number
    }
  }
  vaults: {
    vaultId: string
    kind: "personal"
    role: "owner"
    envelope: string
    attrs: string
    attrsRevision: number
    revision: number
    itemCount: number
    createdAt: number
    updatedAt: number
  }[]
  devices: {
    deviceId: string
    name: string
    platform: string
    createdAt: number
    lastSeenAt: number
  }[]
  reset: null | {
    requestedAt: number
    at: number
  }
  limits: {
    maxItems: number
    maxDevices: 20
  }
}

Errors

StatusMessage
403Passwords opens only in the Authenticator app.
409You already have a vault.
413The request is too large.

PUT /v1/me/vault/keyset

Replaces the sealed keyset after a new master password or Secret Key, if keysetRevision is still current (409 otherwise). Signed by the vault. Emails you.

Auth: user access token or platform agent key

Request body (up to 8 KB)

FieldTypeRequiredNotes
kdfobjectYes
kdf.alg"argon2id"Yes
kdf.mintegerYes
kdf.tintegerYes
kdf.pintegerYes
kdfSaltstringYesmatches ^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$
keysetany JSONYes
keysetRevisionintegerYes≥ 1

Also checked: Unknown fields are rejected.

Response 200

{
  account: {
    createdAt: number
    updatedAt: number
    accountId: string
    kdfSalt: string
    keyset: string
    keysetRevision: number
    encryptionPublicKey: string
    signingPublicKey: string
    kdf: {
      alg: "argon2id"
      m: number
      t: number
      p: number
    }
  }
}

Errors

StatusMessage
403Passwords opens only in the Authenticator app.
409The vault changed on another device.
413The request is too large.

DELETE /v1/me/vault

Signed by the vault: deletes it now (items, vaults, devices and keys; the log stays). Without a signature (you can't open it any more): asks for a reset (202, reset), which may happen 7 days later unless a device that can open the vault cancels it. Emails you either way.

Auth: user access token or platform agent key

Response 200

{
  deleted: true
}

Response 202

{
  reset: {
    requestedAt: number
    at: number
  }
}

Errors

StatusMessage
403Passwords opens only in the Authenticator app.
404There's no vault for this account.

POST /v1/me/vault/reset/cancel

Cancels a pending reset. Signed by the vault.

Auth: user access token or platform agent key

Response 200

{
  reset: null
}

Errors

StatusMessage
403Passwords opens only in the Authenticator app.

GET /v1/me/vault/vaults/:vaultId/index

The vault's counter (revision) and every item's itemId, revision and whether it was deleted, without ciphertext: devices compare it with their copy.

Auth: user access token or platform agent key

Path parameterDescription
:vaultIdA Passwords vault's id: 22 base64url characters, made on the device.

Response 200

{
  revision: number
  items: {
    itemId: string
    revision: number
    deleted: boolean
  }[]
}

Errors

StatusMessage
403Passwords opens only in the Authenticator app.
404That vault isn't yours.

GET /v1/me/vault/vaults/:vaultId/items

Up to 100 items by id (ids, comma-separated): each item's sealed key, overview and details (absent for deleted ones), revision and times.

Auth: user access token or platform agent key

Path parameterDescription
:vaultIdA Passwords vault's id: 22 base64url characters, made on the device.
Query parameterTypeRequiredDefaultNotes
idsstringNo""

Response 200

{
  items: {
    itemId: string
    revision: number
    deleted: boolean
    key?: string
    overview?: string
    details?: string
    createdAt: number
    updatedAt: number
  }[]
}

Errors

StatusMessage
400Ask for up to 100 item ids.
403Passwords opens only in the Authenticator app.
404That vault isn't yours.

POST /v1/me/vault/vaults/:vaultId/items

Writes up to 50 changes (a sealed key, overview and details, or deleted: true), each only if the item is still at its baseRevision (0: new; deletes go first). Per change: ok with the new revision, conflict with the item as it is now, or rejected (limit: the plan's item limit). Signed by the vault.

Auth: user access token or platform agent key

Path parameterDescription
:vaultIdA Passwords vault's id: 22 base64url characters, made on the device.

Request body (up to 4 MB)

FieldTypeRequiredNotes
changesobject[]Yes1–50 items
changes[].itemIdstringYesmatches ^[A-Za-z0-9_-]{22}$
changes[].baseRevisionintegerYes≥ 0
changes[].deletedtrueNo
changes[].keyany JSONNo
changes[].overviewany JSONNo
changes[].detailsany JSONNo

Also checked: Unknown fields are rejected. Each item can change once per request.

Response 200

{
  results: {
    itemId: string
    status: "ok"
    revision: number
    deleted: boolean
    createdAt: number
    updatedAt: number
  } | {
    itemId: string
    status: "conflict"
    current: null | {
      itemId: string
      revision: number
      deleted: boolean
      key?: string
      overview?: string
      details?: string
      createdAt: number
      updatedAt: number
    }
  } | {
    itemId: string
    status: "rejected"
    code: "limit" | "invalid"
    error: string
  }[]
  vault: {
    revision: number
    itemCount: number
  }
}

Errors

StatusMessage
403Passwords opens only in the Authenticator app.
404That vault isn't yours.
413Send fewer changes at once.

PUT /v1/me/vault/devices/:deviceId

Registers this device (name, platform: ios, android or web) or renames it; signed by the vault with the device's own id. Up to 20 devices; a removed id can't come back. Emails you about a new device.

Auth: user access token or platform agent key

Path parameterDescription
:deviceIdDevice id: an agent's (dev_…); under /v1/me/notifications a phone's install id; under /v1/me/sign-in-approvals a phone that approves sign-ins (apd_…); under /v1/me/vault the id a device made for its vault (22 base64url characters).

Request body (up to 4 KB)

FieldTypeRequiredNotes
namestringYes1–80 characters; trimmed
platform"ios" | "android" | "web"Yes

Also checked: Unknown fields are rejected.

Response 200

{
  device: {
    deviceId: string
    name: string
    platform: string
    createdAt: number
    lastSeenAt: number
  }
}

Errors

StatusMessage
403Passwords opens only in the Authenticator app.
403This device was removed from your vault.
409Your vault is on 20 devices already. Remove one first.
413The request is too large.

DELETE /v1/me/vault/devices/:deviceId

Removes a device; it stops syncing and wipes its copy when it next connects. Signed by the vault.

Auth: user access token or platform agent key

Path parameterDescription
:deviceIdDevice id: an agent's (dev_…); under /v1/me/notifications a phone's install id; under /v1/me/sign-in-approvals a phone that approves sign-ins (apd_…); under /v1/me/vault the id a device made for its vault (22 base64url characters).

Response 200

{
  removed: boolean
}

Errors

StatusMessage
400Not a device id.
403Passwords opens only in the Authenticator app.

GET /v1/me/vault/activity

Your vault's log, newest first, kept a year: made, devices added and removed, master password or Secret Key changes, resets, deletion, and counts of changed items. Never contents.

Auth: user access token or platform agent key

Response 200

{
  events: {
    at: number
    counts?: {
      [key: string]: number
    }
    deviceName?: string
    deviceId?: string
    activityId: string
    action: string
  }[]
}

Errors

StatusMessage
403Passwords opens only in the Authenticator app.