Skip to content

Table of contents

Bitwarden

Cozy-stack exposes an API compatible with Bitwarden on /bitwarden.

The author of the unofficial Bitwarden-ruby server did some reverse engineering and wrote a short API documentation.

Setup

The signup is disabled, there is one account per Cozy instance, with the email me@<domain>. When the user chooses his/her password (onboarding), an encryption key is also generated to keep safe the secrets in the bitwarden vault.

Setting a new passphrase

A cozy organization is also created: it will be used to share some passwords with the stack, to be used for the konnectors.

Creating the organization key

The bitwarden clients can connect to the cozy-stack APIs by setting their URL to https://<instance>/bitwarden.

Routes for accounts and connect

POST /bitwarden/api/accounts/prelogin & POST /bitwarden/identity/accounts/prelogin

It allows the client to know the number of KDF iterations to apply when hashing the master password. It can also tell if the login via OIDC is mandatory, if the vault is empty (when both conditions are true, the onboarding process is a bit different), and if flat or nested subdomains are used.

There are 2 routes for the same endpoint, as Bitwarden has moved from the first to the second, and we want to ensure a smooth migration for clients.

Request

POST /bitwarden/identity/accounts/prelogin HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
  "email": "me@alice.example.com"
}

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "Kdf": 0,
  "KdfIterations": 10000,
  "OIDC": false,
  "HasCiphers": true,
  "FlatSubdomains": true
}

POST /bitwarden/identity/connect/token

Request (initial connection)

POST /bitwarden/identity/connect/token HTTP/1.1
Host: alice.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=password&
username=me@alice.example.com&
password=r5CFRR+n9NQI8a525FY+0BPR0HGOjVJX0cR1KEMnIOo=&
scope=api offline_access&
client_id=browser&
deviceType=3&
deviceIdentifier=aac2e34a-44db-42ab-a733-5322dd582c3d&
deviceName=firefox&
clientName=Cozy&
devicePushToken=

If authentication with two factors is enabled on the instance and the user not logged through a web session, this request will fail with a 400 status, but it will send an email with the code. The request can be retried with an additional paramter: twoFactorToken.

Note: the clientName parameter is optional, and is not sent by the official bitwarden clients (a default value is used).

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "client_id": "f05671e159450b44d5c78cebbd0260b5",
  "registration_access_token": "J9l-ZhwP[...omitted for brevity...]",
  "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IkJDMz[...](JWT string)",
  "expires_in": 3600,
  "token_type": "Bearer",
  "refresh_token": "28fb1911ef6db24025ce1bae5aa940e117eb09dfe609b425b69bff73d73c03bf",
  "Key": "0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=",
  "PrivateKey": null
}

Request (refresh token)

POST /bitwarden/identity/connect/token HTTP/1.1
Host: alice.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token&
client_id=browser&
refresh_token=28fb1911ef6db24025ce1bae5aa940e117eb09dfe609b425b69bff73d73c03bf

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IkJDMz[...](JWT string)",
  "expires_in": 3600,
  "token_type": "Bearer",
  "refresh_token": "28fb1911ef6db24025ce1bae5aa940e117eb09dfe609b425b69bff73d73c03bf",
  "Key": "0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ="
}

POST /bitwarden/api/accounts/password-hint

Request

POST /bitwarden/api/accounts/password-hint HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
  "email": "me@alice.example.com"
}

Response

HTTP/1.1 200 OK

GET /bitwarden/api/accounts/profile

Request

GET /bitwarden/api/accounts/profile HTTP/1.1
Host: alice.example.com

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "Id": "0fbfc68d-ba11-416a-ac8a-a82600f0e601",
  "Name": "Alice",
  "Email": "me@alice.example.com",
  "EmailVerified": false,
  "Premium": false,
  "MasterPasswordHint": null,
  "Culture": "en-US",
  "TwoFactorEnabled": false,
  "Key": "0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=",
  "PrivateKey": null,
  "SecurityStamp": "5d203c3f-bc89-499e-85c4-4431248e1196",
  "Organizations": [],
  "Object": "profile"
}

PUT /bitwarden/api/accounts/profile

This route allows to change the profile (currently, only the hint for the master password). It can also be called with a POST (I think it is used by the web vault).

Request

PUT /bitwarden/api/accounts/profile HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
  "masterPasswordHint": "blah blah blah"
}

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "Id": "0fbfc68d-ba11-416a-ac8a-a82600f0e601",
  "Name": "Alice",
  "Email": "me@alice.example.com",
  "EmailVerified": false,
  "Premium": false,
  "MasterPasswordHint": "blah blah blah",
  "Culture": "en-US",
  "TwoFactorEnabled": false,
  "Key": "0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=",
  "PrivateKey": null,
  "SecurityStamp": "5d203c3f-bc89-499e-85c4-4431248e1196",
  "Organizations": [],
  "Object": "profile"
}

POST /bitwarden/api/accounts/keys

This route is used to save a key pair (public and private keys), to be used with organizations.

Request

POST /bitwarden/api/accounts/keys HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
  "encryptedPrivateKey": "2.wZuKkufLV31Cpw1v1TQUDA==|u6bUNTaaGxu...y7s=",
  "publicKey": "MIIBIjANBgkqhkiG9w...AQAB"
}

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "Id": "0fbfc68d-ba11-416a-ac8a-a82600f0e601",
  "Name": "Alice",
  "Email": "me@alice.example.com",
  "EmailVerified": false,
  "Premium": false,
  "MasterPasswordHint": null,
  "Culture": "en-US",
  "TwoFactorEnabled": false,
  "Key": "0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=",
  "PrivateKey": "2.wZuKkufLV31Cpw1v1TQUDA==|u6bUNTaaGxu...y7s=",
  "SecurityStamp": "5d203c3f-bc89-499e-85c4-4431248e1196",
  "Organizations": [],
  "Object": "profile"
}

POST /bitwarden/api/accounts/security-stamp

It allows to set a new security stamp, which has the effect to disconnect all the clients. It can be used, for example, if the encryption key is changed to avoid the clients to corrupt the vault with ciphers encrypted with the old key.

Request

POST /bitwarden/api/accounts/security-stamp HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
  "masterPasswordHash": "r5CFRR+n9NQI8a525FY+0BPR0HGOjVJX0cR1KEMnIOo="
}

Response

HTTP/1.1 204 No Content

GET /bitwarden/api/accounts/revision-date

It returns the date of the last change on the server, as a number of milliseconds since epoch (sic). It is used by the clients to know if they have to do a sync or if they are already up-to-date.

Request

GET /bitwarden/api/accounts/revision-date HTTP/1.1
Host: alice.example.com

Response

HTTP/1.1 200 OK

1569571388892

PUT /bitwarden/api/settings/domains

This route is also available via a POST, for compatibility with the web vault.

Request

PUT /bitwarden/api/settings/domains HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
  "equivalentDomains": [
    ["stackoverflow.com", "serverfault.com", "superuser.com"]
  ],
  "globalEquivalentDomains": [42, 69]
}

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "EquivalentDomains": [
    ["stackoverflow.com", "serverfault.com", "superuser.com"]
  ],
  "GlobalEquivalentDomains": [
    { "Type": 2, "Domains": ["ameritrade.com", "tdameritrade.com"], "Excluded": false },
    { "Type": 3, "Domains": ["bankofamerica.com", "bofa.com", "mbna.com", "usecfo.com"], "Excluded": false },
    { "Type": 42, "Domains": ["playstation.com", "sonyentertainmentnetwork.com"], "Excluded": true },
    { "Type": 69, "Domains": ["morganstanley.com", "morganstanleyclientserv.com"], "Excluded": true }
  ],
  "Object": "domains"
}

GET /bitwarden/api/settings/domains

Request

GET /bitwarden/api/settings/domains HTTP/1.1
Host: alice.example.com

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "EquivalentDomains": [
    ["stackoverflow.com", "serverfault.com", "superuser.com"]
  ],
  "GlobalEquivalentDomains": [
    { "Type": 2, "Domains": ["ameritrade.com", "tdameritrade.com"], "Excluded": false },
    { "Type": 3, "Domains": ["bankofamerica.com", "bofa.com", "mbna.com", "usecfo.com"], "Excluded": false },
    { "Type": 42, "Domains": ["playstation.com", "sonyentertainmentnetwork.com"], "Excluded": true },
    { "Type": 69, "Domains": ["morganstanley.com", "morganstanleyclientserv.com"], "Excluded": true }
  ],
  "Object": "domains"
}

Route for sync

GET /bitwarden/api/sync

The main action of the client is a one-way sync, which just fetches all objects from the server and updates its local database.

Request

GET /bitwarden/api/sync HTTP/1.1

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "Profile": {
    "Id": "0fbfc68d-ba11-416a-ac8a-a82600f0e601",
    "Name": "Alice",
    "Email": "me@alice.example.com",
    "EmailVerified": false,
    "Premium": false,
    "MasterPasswordHint": null,
    "Culture": "en-US",
    "TwoFactorEnabled": false,
    "Key": "0.uRcMe+Mc2nmOet4yWx9BwA==|PGQhpYUlTUq/vBEDj1KOHVMlTIH1eecMl0j80+Zu0VRVfFa7X/MWKdVM6OM/NfSZicFEwaLWqpyBlOrBXhR+trkX/dPRnfwJD2B93hnLNGQ=",
    "PrivateKey": null,
    "SecurityStamp": "5d203c3f-bc89-499e-85c4-4431248e1196",
    "Organizations": [
      {
        "Id": "38ac39d0-d48d-11e9-91bf-f37e45d48c79",
        "Name": "Cozy",
        "Key": "4.HUzVDQVAFc4JOpW3/j/QwZeET0mXOiDW5s/HdpxLZ2GFnGcxOm1FE4XD2p7XTSwORXO/Lo8y0A87UhXKEXzfHZmpJR04pbpUPr4NJbjRKv/cSkNFlvm0rIUw/m0Jkft/gew9v3QfkVSGdSZk5XIimwkTQ5WM+WCStxbQJIKAH+AoEA5q6t9mpNNlTAQvMgqs8u7CJwSjeZ7qbabfEUVX1HIPgxC3BtVUkySRSws/gUNeMwY23kAJJQYT+uuMooZUr7umU6YkEHG2RQZwCCjVHX4czxZRWsVo/xQOYoNr7DjgCf92D7OrJlFmDtQjzSy2BjotN6vn+1SwtHbeDILWaQ==",
        "BillingEmail": "me@cozy.localhost",
        "Plan": "TeamsAnnually",
        "PlanType": 5,
        "Seats": 2,
        "MaxCollections": 1,
        "MaxStorageGb": 1,
        "SelfHost": true,
        "Use2fa": true,
        "UseDirectory": false,
        "UseEvents": false,
        "UseGroups": false,
        "UseTotp": true,
        "UsersGetPremium": true,
        "Enabled": true,
        "Status": 2,
        "Type": 2,
        "Object": "profileOrganization"
      }
    ],
    "Object": "profile"
  },
  "Folders": [
    {
      "Id": "14220912-d002-471d-a364-a82a010cb8f2",
      "Name": "2.tqb+y2z4ChCYHj4romVwGQ==|E8+D7aR5CNnd+jF7fdb9ow==|wELCxyy341G2F+w8bTb87PAUi6sdXeIFTFb4N8tk3E0=",
      "RevisionDate": "2017-11-13T16:20:56.5633333",
      "Object": "folder"
    }
  ],
  "Ciphers": [
    {
      "FolderId": null,
      "Favorite": false,
      "Edit": true,
      "Id": "0f01a66f-7802-42bc-9647-a82600f11e10",
      "OrganizationId": null,
      "Type": 1,
      "Login": {
        "Uris": [
          {
            "Uri": "2.6DmdNKlm3a+9k/5DFg+pTg==|7q1Arwz/ZfKEx+fksV3yo0HMQdypHJvyiix6hzgF3gY=|7lSXqjfq5rD3/3ofNZVpgv1ags696B2XXJryiGjDZvk=",
            "Match": null
          }
        ],
        "Username": "2.4Dwitdv4Br85MABzhMJ4hg==|0BJtHtXbfZWwQXbFcBn0aA==|LM4VC+qNpezmub1f4l1TMLDb9g/Q+sIis2vDbU32ZGA=",
        "Password": "2.OOlWRBGib6G8WRvBOziKzQ==|Had/obAdd2/6y4qzM1Kc/A==|LtHXwZc5PkiReFhkzvEHIL01NrsWGvintQbmqwxoXSI=",
        "Totp": null
      },
      "Name": "2.zAgCKbTvGowtaRn1er5WGA==|oVaVLIjfBQoRr5EvHTwfhQ==|lHSTUO5Rgfkjl3J/zGJVRfL8Ab5XrepmyMv9iZL5JBE=",
      "Notes": "2.NLkXMHtgR8u9azASR4XPOQ==|6/9QPcnoeQJDKBZTjcBAjVYJ7U/ArTch0hUSHZns6v8=|p55cl9FQK/Hef+7yzM7Cfe0w07q5hZI9tTbxupZepyM=",
      "Fields": null,
      "Attachments": null,
      "OrganizationUseTotp": false,
      "RevisionDate": "2017-11-09T14:37:52.9033333",
      "Object": "cipher"
    }
  ],
  "Collections": [
    {
      "Id": "385aaa2a-d48d-11e9-bb5f-6b31dfebcb4d",
      "OrganizationId": "38ac39d0-d48d-11e9-91bf-f37e45d48c79",
      "Name": "2.PowfE263ZLz7+Jqrpuezqw==|OzuXDsJnQdfa/eMKxsms6Q==|RpEB7qqs26X9dqa+KaxSE5+52TFVs4dAdfU7DCu3QXM=",
      "Object": "collection",
      "ReadOnly": false
    }
  ],
  "Domains": {
    "EquivalentDomains": null,
    "GlobalEquivalentDomains": null,
    "Object": "domains"
  },
  "Object": "sync"
}

Routes for ciphers

GET /bitwarden/api/ciphers

It retrieves the list of ciphers.

Request

GET /bitwarden/api/ciphers HTTP/1.1

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "Data": [
    {
      "Object": "cipher",
      "Id": "4c2869dd-0e1c-499f-b116-a824016df251",
      "Type": 1,
      "Favorite": false,
      "Name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=",
      "FolderId": null,
      "OrganizationId": null,
      "Notes": null,
      "Login": {
        "Uris": [
          {
            "Uri": "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=",
            "Match": null
          }
        ]
      },
      "Username": "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=",
      "Password": "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=",
      "Totp": null,
      "Fields": null,
      "Attachments": null,
      "RevisionDate": "2017-11-07T22:12:22.235914Z",
      "Edit": true,
      "OrganizationUseTotp": false
    }
  ],
  "Object": "list"
}

POST /bitwarden/api/ciphers

When a new item (login, secure note, etc.) is created on a device, it is sent to the server with its fields encrypted via this route.

Request

POST /bitwarden/api/ciphers HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
    "type": 1,
    "favorite": false,
    "name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=",
    "folderId": null,
    "organizationId": null,
    "notes": null,
    "login": {
        "uri": "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=",
        "username": "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=",
        "password": "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=",
        "totp": null
    }
}

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
    "Object": "cipher",
    "Id": "4c2869dd-0e1c-499f-b116-a824016df251",
    "Type": 1,
    "Favorite": false,
    "Name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=",
    "FolderId": null,
    "OrganizationId": null,
    "Notes": null,
    "Login": {
        "Uris": [
            {
                "Uri": "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=",
                "Match": null
            }
        ]
    },
    "Username": "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=",
    "Password": "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=",
    "Totp": null,
    "Fields": null,
    "Attachments": null,
    "RevisionDate": "2017-11-07T22:12:22.235914Z",
    "Edit": true,
    "OrganizationUseTotp": false
}

POST /bitwarden/api/ciphers/create

This route also allows to create a cipher, but this time, it is for a cipher shared with an organization.

Request

POST /bitwarden/api/ciphers/create HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
  "cipher": {
    "type": 1,
    "favorite": false,
    "name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=",
    "folderId": null,
    "organizationId": "38ac39d0-d48d-11e9-91bf-f37e45d48c79",
    "notes": null,
    "login": {
      "uri": "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=",
      "username": "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=",
      "password": "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=",
      "totp": null
    }
  },
  "collectionIds": ["385aaa2a-d48d-11e9-bb5f-6b31dfebcb4d"]
}

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
    "Object": "cipher",
    "Id": "4c2869dd-0e1c-499f-b116-a824016df251",
    "Type": 1,
    "Favorite": false,
    "Name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=",
    "FolderId": null,
    "OrganizationId": "38ac39d0-d48d-11e9-91bf-f37e45d48c79",
    "Notes": null,
    "Login": {
        "Uris": [
            {
                "Uri": "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=",
                "Match": null
            }
        ]
    },
    "Username": "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=",
    "Password": "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=",
    "Totp": null,
    "Fields": null,
    "Attachments": null,
    "RevisionDate": "2017-11-07T22:12:22.235914Z",
    "Edit": true,
    "OrganizationUseTotp": false
}

GET /bitwarden/api/ciphers/:id and /bitwarden/api/ciphers/:id/details

Request

GET /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251 HTTP/1.1

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
    "Object": "cipher",
    "Id": "4c2869dd-0e1c-499f-b116-a824016df251",
    "Type": 1,
    "Favorite": false,
    "Name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=",
    "FolderId": null,
    "OrganizationId": null,
    "Notes": null,
    "Login": {
        "Uris": [
            {
                "Uri": "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=",
                "Match": null
            }
        ]
    },
    "Username": "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=",
    "Password": "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=",
    "Totp": null,
    "Fields": null,
    "Attachments": null,
    "RevisionDate": "2017-11-07T22:12:22.235914Z",
    "Edit": true,
    "OrganizationUseTotp": false
}

PUT /bitwarden/api/ciphers/:id

This route is used to change a cipher. It can also be called via POST /bitwarden/api/ciphers/:id (I think it is used by the web vault).

Request

PUT /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251 HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
    "type": 2,
    "favorite": true,
    "name": "2.G38TIU3t1pGOfkzjCQE7OQ==|Xa1RupttU7zrWdzIT6oK+w==|J3C6qU1xDrfTgyJD+OrDri1GjgGhU2nmRK75FbZHXoI=",
    "folderId": "14220912-d002-471d-a364-a82a010cb8f2",
    "organizationId": null,
    "notes": "2.rSw0uVQEFgUCEmOQx0JnDg==|MKqHLD25aqaXYHeYJPH/mor7l3EeSQKsI7A/R+0bFTI=|ODcUScISzKaZWHlUe4MRGuTT2S7jpyDmbOHl7d+6HiM=",
    "secureNote": {
        "type": 0
    }
}

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
    "Object": "cipher",
    "Id": "4c2869dd-0e1c-499f-b116-a824016df251",
    "Type": 2,
    "Favorite": true,
    "Name": "2.G38TIU3t1pGOfkzjCQE7OQ==|Xa1RupttU7zrWdzIT6oK+w==|J3C6qU1xDrfTgyJD+OrDri1GjgGhU2nmRK75FbZHXoI=",
    "FolderId": "14220912-d002-471d-a364-a82a010cb8f2",
    "OrganizationId": null,
    "Notes": "2.rSw0uVQEFgUCEmOQx0JnDg==|MKqHLD25aqaXYHeYJPH/mor7l3EeSQKsI7A/R+0bFTI=|ODcUScISzKaZWHlUe4MRGuTT2S7jpyDmbOHl7d+6HiM=",
  "SecureNote": {
    "Type": 0
  },
    "Fields": null,
    "Attachments": null,
    "RevisionDate": "2017-11-07T22:12:22.235914Z",
    "Edit": true,
    "OrganizationUseTotp": false
}

POST /bitwarden/api/ciphers/:id/share

This route is used to share a cipher with an organization. The fields must be encrypted with the organization key.

Request

POST /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251/share HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
  "cipher": {
    "type": 2,
    "favorite": true,
    "name": "2.d00W2bB8LhE86LybnoPnEQ==|QqJqmzMMv2Cdm9wieUH66Q==|TV++tKNF0+4/axjAeRXMxAkTdRBuIsXnCuhOKE0ESh0=",
    "organizationId": "38ac39d0-d48d-11e9-91bf-f37e45d48c79",
    "notes": "2.9m3XIbiJLk86thmF3UsO/A==|YC7plTgNQuMCkzYZC3iRjQ==|o8wZNQ3czr9sdeGXjOCalQwgPWsqOHZVnA2utZ+o/l4=",
    "secureNote": {
      "type": 0
    }
  },
  "collectionIds": ["385aaa2a-d48d-11e9-bb5f-6b31dfebcb4d"]
}

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
    "Object": "cipher",
    "Id": "4c2869dd-0e1c-499f-b116-a824016df251",
    "Type": 2,
    "Favorite": true,
  "Name": "2.d00W2bB8LhE86LybnoPnEQ==|QqJqmzMMv2Cdm9wieUH66Q==|TV++tKNF0+4/axjAeRXMxAkTdRBuIsXnCuhOKE0ESh0=",
  "OrganizationId": "38ac39d0-d48d-11e9-91bf-f37e45d48c79",
  "Notes": "2.9m3XIbiJLk86thmF3UsO/A==|YC7plTgNQuMCkzYZC3iRjQ==|o8wZNQ3czr9sdeGXjOCalQwgPWsqOHZVnA2utZ+o/l4=",
  "SecureNote": {
    "Type": 0
  },
    "Fields": null,
    "Attachments": null,
    "RevisionDate": "2017-11-07T22:12:22.235914Z",
    "Edit": true,
    "OrganizationUseTotp": false
}

DELETE /bitwarden/api/ciphers/:id

This route is used to delete a cipher. It can also be called via POST /bitwarden/api/ciphers/:id/delete (I think it is used by the web vault).

Request

DELETE /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251 HTTP/1.1
Host: alice.example.com

Response

HTTP/1.1 200 OK

DELETE /bitwarden/api/ciphers

This route is used to delete ciphers in bulk. It can also be called via POST /bitwarden/api/ciphers/delete.

Request

DELETE /bitwarden/api/ciphers HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
  "ids": [
    "4c2869dd-0e1c-499f-b116-a824016df251",
    "205c22f0-8642-0139-c874-543d7eb8149c"
  ]
}

Response

HTTP/1.1 200 OK

PUT /bitwarden/api/ciphers/:id/delete

This route is used to soft delete a cipher, by adding a deletedDate attribute on it.

Request

PUT /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251/delete HTTP/1.1
Host: alice.example.com

Response

HTTP/1.1 204 No Content

PUT /bitwarden/api/ciphers/delete

This route is used to soft delete ciphers in bulk.

Request

PUT /bitwarden/api/ciphers/delete HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
  "ids": [
    "4c2869dd-0e1c-499f-b116-a824016df251",
    "205c22f0-8642-0139-c874-543d7eb8149c"
  ]
}

Response

HTTP/1.1 200 OK

PUT /bitwarden/api/ciphers/:id/restore

This route is used to restore a soft-deleted cipher, by removing the deletedDate attribute.

Request

PUT /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251/restore HTTP/1.1
Host: alice.example.com

Response

HTTP/1.1 204 No Content

PUT /bitwarden/api/ciphers/restore

This route is used to restore ciphers in bulk.

Request

PUT /bitwarden/api/ciphers/restore HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
  "ids": [
    "4c2869dd-0e1c-499f-b116-a824016df251",
    "205c22f0-8642-0139-c874-543d7eb8149c"
  ]
}

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "Data": [
    {
      "Object": "cipher",
      "Id": "4c2869dd-0e1c-499f-b116-a824016df251",
      "Type": 1,
      "Favorite": false,
      "Name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=",
      "FolderId": null,
      "OrganizationId": null,
      "Notes": null,
      "Login": {
        "Uris": [
          {
            "Uri": "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=",
            "Match": null
          }
        ]
      },
      "Username": "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=",
      "Password": "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=",
      "Totp": null,
      "Fields": null,
      "Attachments": null,
      "RevisionDate": "2021-04-23T12:58:01Z",
      "Edit": true,
      "OrganizationUseTotp": false
    },
    {
      "Object": "cipher",
      "Id": "205c22f0-8642-0139-c874-543d7eb8149c",
      "Type": 2,
      "Favorite": true,
      "Name": "2.G38TIU3t1pGOfkzjCQE7OQ==|Xa1RupttU7zrWdzIT6oK+w==|J3C6qU1xDrfTgyJD+OrDri1GjgGhU2nmRK75FbZHXoI=",
      "FolderId": null,
      "OrganizationId": null,
      "Notes": "2.rSw0uVQEFgUCEmOQx0JnDg==|MKqHLD25aqaXYHeYJPH/mor7l3EeSQKsI7A/R+0bFTI=|ODcUScISzKaZWHlUe4MRGuTT2S7jpyDmbOHl7d+6HiM=",
      "RevisionDate": "2021-04-23T12:58:01Z",
      "Edit": true,
      "OrganizationUseTotp": false
    }
  ],
  "Object": "list"
}

POST /bitwarden/api/ciphers/import

This route can be used to import several ciphers and folders in bulk.

In folderRelationships, the key is the index of the cipher in the ciphers list, and the value is the index of the folder in the folders list.

Request

POST /bitwarden/api/ciphers/import HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
  "ciphers": [{
    "type": 2,
    "favorite": true,
    "name": "2.G38TIU3t1pGOfkzjCQE7OQ==|Xa1RupttU7zrWdzIT6oK+w==|J3C6qU1xDrfTgyJD+OrDri1GjgGhU2nmRK75FbZHXoI=",
    "folderId": null,
    "organizationId": null,
    "notes": "2.rSw0uVQEFgUCEmOQx0JnDg==|MKqHLD25aqaXYHeYJPH/mor7l3EeSQKsI7A/R+0bFTI=|ODcUScISzKaZWHlUe4MRGuTT2S7jpyDmbOHl7d+6HiM=",
    "secureNote": {
      "type": 0
    }
  }, {
    "type": 1,
    "favorite": false,
    "name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=",
    "folderId": null,
    "organizationId": null,
    "notes": null,
    "login": {
      "uri": "2.T57BwAuV8ubIn/sZPbQC+A==|EhUSSpJWSzSYOdJ/AQzfXuUXxwzcs/6C4tOXqhWAqcM=|OWV2VIqLfoWPs9DiouXGUOtTEkVeklbtJQHkQFIXkC8=",
      "username": "2.JbFkAEZPnuMm70cdP44wtA==|fsN6nbT+udGmOWv8K4otgw==|JbtwmNQa7/48KszT2hAdxpmJ6DRPZst0EDEZx5GzesI=",
      "password": "2.e83hIsk6IRevSr/H1lvZhg==|48KNkSCoTacopXRmIZsbWg==|CIcWgNbaIN2ix2Fx1Gar6rWQeVeboehp4bioAwngr0o=",
      "totp": null
    }
  }],
  "folders": [{
    "name": "2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o="
  }],
  "folderRelationships": [
    {"key": 1, "value": 0}
  ]
}

Response

HTTP/1.1 204 No Content

Routes for folders

GET /bitwarden/api/folders

It retrieves the list of folders.

Request

GET /bitwarden/api/folders HTTP/1.1

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "Data": [
    {
      "Id": "14220912-d002-471d-a364-a82a010cb8f2",
      "Name": "2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o=",
      "RevisionDate": "2017-11-13T16:18:23.3078169Z",
      "Object": "folder"
    }
  ],
  "Object": "list"
}

POST /bitwarden/api/folders

It adds a new folder on the server. The name is encrypted on client-side.

Request

POST /bitwarden/api/folders HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
  "name": "2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o="
}

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
    "Id": "14220912-d002-471d-a364-a82a010cb8f2",
    "Name": "2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o=",
    "RevisionDate": "2017-11-13T16:18:23.3078169Z",
    "Object": "folder"
}

GET /bitwarden/api/folders/:id

Request

GET /bitwarden/api/folders/14220912-d002-471d-a364-a82a010cb8f2 HTTP/1.1

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
    "Id": "14220912-d002-471d-a364-a82a010cb8f2",
    "Name": "2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o=",
    "RevisionDate": "2017-11-13T16:18:23.3078169Z",
    "Object": "folder"
}

PUT /bitwarden/api/folders/:id

This route is used to rename a folder. It can also be called via POST /bitwarden/api/folders/:id (I think it is used by the web vault).

Request

PUT /bitwarden/api/folders/14220912-d002-471d-a364-a82a010cb8f2 HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
  "name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io="
}

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
    "Id": "14220912-d002-471d-a364-a82a010cb8f2",
    "Name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io=",
    "RevisionDate": "2017-11-13T16:18:23.3078169Z",
    "Object": "folder"
}

DELETE /bitwarden/api/folders/:id

This route is used to delete a folder. It can also be called via POST /bitwarden/api/folders/:id/delete (I think it is used by the web vault).

Request

DELETE /bitwarden/api/folders/14220912-d002-471d-a364-a82a010cb8f2 HTTP/1.1
Host: alice.example.com

Response

HTTP/1.1 200 OK

Organizations and Collections

GET /bitwarden/organizations/cozy

This route can be used to get information about the Cozy Organization. It requires a permission on the whole com.bitwarden.organizations doctype to access it. In particular, it gives the key to encrypt/decrypt the ciphers in this organization (encoded in base64).

Request

GET /bitwarden/organizations/cozy HTTP/1.1
Host: alice.example.com

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "organizationId": "38ac39d0-d48d-11e9-91bf-f37e45d48c79",
  "collectionId": "385aaa2a-d48d-11e9-bb5f-6b31dfebcb4d",
  "organizationKey": "oWeRYokoCMFsAja6lrp3RQ1PYOrex4tgAMECP4nX+a4IXdijbejQscvWqy9bMgLsX0HRc2igqBRMWdsPuFK0PQ=="
}

POST /bitwarden/api/organizations

This route can be used to create an organization, with a collection.

Request

POST /bitwarden/api/organizations HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
  "name": "Family",
  "key": "4.bmFjbF53D9mrdGbVqQzMB54uIg678EIpU/uHFYjynSPSA6vIv5/6nUy4Uk22SjIuDB3pZ679wLE3o7R/Imzn47OjfT6IrJ8HaysEhsZA25Dn8zwEtTMtgNepUtH084wAMgNeIcElW24U/MfRscjAk8cDUIm5xnzyi2vtJfe9PcHTmzRXyng=",
  "collectionName": "2.rrpSDDODsWZqL7EhLVsu/Q==|OSuh+MmmR89ppdb/A7KxBg==|kofpAocL2G4a3P1C2R1U+i9hWbhfKfsPKM6kfoyCg/M="
}

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "Id": "724db920-cc4b-0139-6ab2-543d7eb8149c",
  "Name": "Family",
  "Key": "4.bmFjbF53D9mrdGbVqQzMB54uIg678EIpU/uHFYjynSPSA6vIv5/6nUy4Uk22SjIuDB3pZ679wLE3o7R/Imzn47OjfT6IrJ8HaysEhsZA25Dn8zwEtTMtgNepUtH084wAMgNeIcElW24U/MfRscjAk8cDUIm5xnzyi2vtJfe9PcHTmzRXyng=",
  "BillingEmail": "me@cozy.localhost",
  "Plan": "TeamsAnnually",
  "PlanType": 9,
  "Seats": 10,
  "MaxCollections": 1,
  "MaxStorageGb": 1,
  "SelfHost": true,
  "Use2fa": true,
  "UseDirectory": false,
  "UseEvents": false,
  "UseGroups": false,
  "UseTotp": true,
  "UseApi": false,
  "UsePolicies": false,
  "UseSSO": false,
  "UseResetPass": false,
  "HasPublicAndPrivateKeys": false,
  "ResetPasswordEnrolled": false,
  "UsersGetPremium": true,
  "Enabled": true,
  "Status": 2,
  "Type": 2,
  "Object": "profileOrganization"
}

GET /bitwarden/api/organizations/:id

This route can be used to fetch information about an organization.

Request

GET /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c HTTP/1.1
Host: alice.example.com

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "Id": "724db920-cc4b-0139-6ab2-543d7eb8149c",
  "Name": "Family",
  "Key": "4.bmFjbF53D9mrdGbVqQzMB54uIg678EIpU/uHFYjynSPSA6vIv5/6nUy4Uk22SjIuDB3pZ679wLE3o7R/Imzn47OjfT6IrJ8HaysEhsZA25Dn8zwEtTMtgNepUtH084wAMgNeIcElW24U/MfRscjAk8cDUIm5xnzyi2vtJfe9PcHTmzRXyng=",
  "BillingEmail": "me@cozy.localhost",
  "Plan": "TeamsAnnually",
  "PlanType": 9,
  "Seats": 10,
  "MaxCollections": 1,
  "MaxStorageGb": 1,
  "SelfHost": true,
  "Use2fa": true,
  "UseDirectory": false,
  "UseEvents": false,
  "UseGroups": false,
  "UseTotp": true,
  "UseApi": false,
  "UsePolicies": false,
  "UseSSO": false,
  "UseResetPass": false,
  "HasPublicAndPrivateKeys": false,
  "ResetPasswordEnrolled": false,
  "UsersGetPremium": true,
  "Enabled": true,
  "Status": 2,
  "Type": 2,
  "Object": "profileOrganization"
}

GET /bitwarden/api/organizations/:id/collections

This route can be used to fetch information about the collections inside an organization.

Request

GET /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c/collections HTTP/1.1
Host: alice.example.com

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "Data": [
    {
      "Id": "62080a40-d75d-0139-21f1-543d7eb8149c",
      "OrganizationId": "724db920-cc4b-0139-6ab2-543d7eb8149c",
      "Name": "2.rrpSDDODsWZqL7EhLVsu/Q==|OSuh+MmmR89ppdb/A7KxBg==|kofpAocL2G4a3P1C2R1U+i9hWbhfKfsPKM6kfoyCg/M=",
      "Object": "collection"
    }
  ],
  "Object": "list"
}

DELETE /bitwarden/api/organizations/:id

This route can be used to delete an organization by its owner.

Request

DELETE /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
  "masterPasswordHash": "r5CFRR+n9NQI8a525FY+0BPR0HGOjVJX0cR1KEMnIOo="
}

Response

HTTP/1.1 200 OK

GET /bitwarden/api/organizations/:id/users

This route returns the list of users in the given organization.

Request

GET /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c/users HTTP/1.1
Host: alice.example.com

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "Data": [
    {
      "Object": "organizationUserUserDetails",
      "Id": "0fbfc68d-ba11-416a-ac8a-a82600f0e601",
      "UserId": "0fbfc68d-ba11-416a-ac8a-a82600f0e601",
      "Type": 0,
      "Status": 2,
      "AccessAll": true,
      "Name": "Alice",
      "Email": "alice@example.com"
    },
    {
      "Object": "organizationUserUserDetails",
      "Id": "89d99af0db1c0139605b543d7eb8149c",
      "UserId": "89d99af0db1c0139605b543d7eb8149c",
      "Type": 2,
      "Status": 1,
      "AccessAll": true,
      "Name": "Bob",
      "Email": "bob@example.com"
    }
  ],
  "Object": "list"
}

POST /bitwarden/api/organizations/:id/users/:user-id/confirm

This route is used by the owner of an organization to confirm that another user can use this sharing. The caller must check the fingerprint of the new member and encrypt the organization key with their public key.

Request

POST /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c/users/89d99af0db1c0139605b543d7eb8149c/confirm HTTP/1.1
Host: alice.example.com
Content-Type: application/json
{
  "key": "4.UT/TVY6qmAjNdax2WT9JcA97wSWvEudAlqpjfxrFUieOoGA88MxzbYjpCXajEST/PehD1I7KC93jwthng772extu+lLHSd/Ce+a5Qw8+pRxL7je8QgS8gmP0FhfRLc4bl5hUMTfQcUDiuiiNaDez6E9czOzk9iuVaGpEjK4YAYgQy25m3eGc+DTPv8206NJZ/lr8CpPyhwUHjtDhlOZnDWAf+a28x2EAj1ogZKKJGAUcRENitV8Joa7OGRO6dmxtTTnWOuPDk5DajGgzpIQURNuotVHcpBtCL8HzNAduQ9vtrPKJtyAsHRdjau2SwEnaLZmxAvp7d9VG3t5nDYtgWA=="
}

Response

HTTP/1.1 200 OK

GET /bitwarden/api/users/:id/public-key

This route gives the public key of a user.

Request

GET /bitwarden/api/users/89d99af0db1c0139605b543d7eb8149c/public-key HTTP/1.1
Host: alice.example.com

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "UserId": "89d99af0db1c0139605b543d7eb8149c",
  "PublicKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1LwbnLsT8w2OBPR/zy/zRQNH+jZzD6v4qUGAJg0NfoUkBSgtq9yjor2GgeRtdf8VuNTn1kcNrUIU4f9vE3ppNJgmUss4O29OP9/ATqtC/4ri4UCWTV0DPCF4gRU1SbgTg9O3yC2UYWmrs47SgU0wwT+f5AjfDC7GzhjyX68UYIIIeKSMZasjcy+wIPVAW0hYhcEoK3Coq2O1wVwM+b2fXPIMzn38onUTbMCrkVY+FzGg6NtZbKzPvVZ0iyfQ6BxvttqSViNPOpyz7gryDhgYKokV+kwj5ARDZWL6ml73U2lL7uapk5meNKZf8w7TJGepFiewGLm08VMht6lnIZBuDQIDAQAB"
}

DELETE /bitwarden/contacts/:id

This route can be used to refuse to give access to a user to shared ciphers. The contact will be deleted, and they will be revoked from all sharings.

Request

GET /bitwarden/contacts/89d99af0db1c0139605b543d7eb8149c HTTP/1.1
Host: alice.example.com

Response

HTTP/1.1 204 No-Content

Icons

GET /bitwarden/icons/:domain/icon.png

This route returns an icon for the given domain, that can be used by the bitwarden clients. No authorization token is required.

If no favicon has been found for the domain, a fallback will be used, depending of the fallback parameter in the query-string:

  • default: a default icon is returned
  • 404: just a 404 - Not found error.

Request

GET /bitwarden/icons/cozy.io/icon.png HTTP/1.1
Host: alice.example.com

Hub

The hub is a way to get notifications in real-time about cipher and folder changes.

POST /bitwarden/notifications/hub/negotiate

Before connecting to the hub, the client make a request to this endpoint to know what are the transports and formats supported by the server.

Request

POST /bitwarden/notifications/hub/negotiate HTTP/1.1
Host: alice.example.com

Response

HTTP/1.1 200 OK
Content-Type: application/json
{
  "connectionId": "NzhhYjU4NjgtZTA1NC0xMWU5LWIzNzAtM2I1YzM3YWQyOTc1Cg",
  "availableTransports": [
    { "Transport": "WebSockets", "Formats": ["Binary"] }
  ]
}

GET /bitwarden/notifications/hub

This endpoint is used for WebSockets to get the notifications in real-time. The client must do 3 things, in this order:

  1. Make the HTTP request, with the token in the query string (access_token)
  2. Upgrade the connection to WebSockets
  3. Send JSON payload with {"protocol": "messagepack", "version": 1}.