Ctrl K
ComunidadGuías…

docs/bitwarden.md

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
[Table of contents](README.md#table-of-contents)

# Bitwarden

Cozy-stack exposes an API compatible with
[Bitwarden](https://github.com/bitwarden) on `/bitwarden`.

The author of the [unofficial Bitwarden-ruby
server](https://github.com/jcs/rubywarden) did some reverse engineering and
wrote a short [API
documentation](https://github.com/jcs/rubywarden/blob/master/API.md).

## 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](diagrams/bitwarden-onboarding.png)

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](diagrams/bitwarden-organization.png)

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

## Routes for accounts and connect

### GET /bitwarden/api/config

Bitwarden clients require this route, even if the information could be guessed
without it in Cozy case.

#### Request

```http
GET /bitwarden/api/config HTTP/1.1
Host: alice.example.com
```

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```json
{
  "version": "2024.0.0",
  "gitHash": null,
  "server": null,
  "environment": {
    "cloudRegion": "EU",
    "vault": "https://alice.example.com",
    "api": "https://alice.example.com",
    "identity": "https://alice.example.com",
    "notifications": "https://alice.example.com"
  },
  "featureStates": {},
  "object": "config"
}
```

### 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

```http
POST /bitwarden/identity/accounts/prelogin HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```json
{
  "email": "me@alice.example.com"
}
```

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```json
{
  "Kdf": 0,
  "KdfIterations": 10000,
  "OIDC": false,
  "HasCiphers": true,
  "FlatSubdomains": true,
  "Salt": "me@alice.example.com"
}
```

### POST /bitwarden/identity/connect/token

#### Request (initial connection)

```http
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
HTTP/1.1 200 OK
Content-Type: application/json
```

```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)

```http
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
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

```http
POST /bitwarden/api/accounts/password-hint HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```json
{
  "email": "me@alice.example.com"
}
```

#### Response

```http
HTTP/1.1 200 OK
```

### GET /bitwarden/api/accounts/profile

#### Request

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

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

```http
PUT /bitwarden/api/accounts/profile HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```json
{
  "masterPasswordHint": "blah blah blah"
}
```

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

```http
POST /bitwarden/api/accounts/keys HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```json
{
  "encryptedPrivateKey": "2.wZuKkufLV31Cpw1v1TQUDA==|u6bUNTaaGxu...y7s=",
  "publicKey": "MIIBIjANBgkqhkiG9w...AQAB"
}
```

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

```http
POST /bitwarden/api/accounts/security-stamp HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```json
{
  "masterPasswordHash": "r5CFRR+n9NQI8a525FY+0BPR0HGOjVJX0cR1KEMnIOo="
}
```

#### Response

```http
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

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

#### Response

```http
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

```http
PUT /bitwarden/api/settings/domains HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```json
{
  "equivalentDomains": [
    ["stackoverflow.com", "serverfault.com", "superuser.com"]
  ],
  "globalEquivalentDomains": [42, 69]
}
```

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

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

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

```http
GET /bitwarden/api/sync HTTP/1.1
```

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

```http
GET /bitwarden/api/ciphers HTTP/1.1
```

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

```http
POST /bitwarden/api/ciphers HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```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
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

```http
POST /bitwarden/api/ciphers/create HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```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
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

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

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

```http
PUT /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251 HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```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
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

```http
POST /bitwarden/api/ciphers/4c2869dd-0e1c-499f-b116-a824016df251/share HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```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
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

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

#### Response

```http
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

```http
DELETE /bitwarden/api/ciphers HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```json
{
  "ids": [
    "4c2869dd-0e1c-499f-b116-a824016df251",
    "205c22f0-8642-0139-c874-543d7eb8149c"
  ]
}
```

#### Response

```http
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

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

#### Response

```http
HTTP/1.1 204 No Content
```

### PUT /bitwarden/api/ciphers/delete

This route is used to soft delete ciphers in bulk.

#### Request

```http
PUT /bitwarden/api/ciphers/delete HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```json
{
  "ids": [
    "4c2869dd-0e1c-499f-b116-a824016df251",
    "205c22f0-8642-0139-c874-543d7eb8149c"
  ]
}
```

#### Response

```http
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

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

#### Response

```http
HTTP/1.1 204 No Content
```

### PUT /bitwarden/api/ciphers/restore

This route is used to restore ciphers in bulk.

#### Request

```http
PUT /bitwarden/api/ciphers/restore HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```json
{
  "ids": [
    "4c2869dd-0e1c-499f-b116-a824016df251",
    "205c22f0-8642-0139-c874-543d7eb8149c"
  ]
}
```

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

```http
POST /bitwarden/api/ciphers/import HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```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
HTTP/1.1 204 No Content
```

## Routes for folders

### GET /bitwarden/api/folders

It retrieves the list of folders.

#### Request

```http
GET /bitwarden/api/folders HTTP/1.1
```

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

```http
POST /bitwarden/api/folders HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```json
{
  "name": "2.FQAwIBaDbczEGnEJw4g4hw==|7KreXaC0duAj0ulzZJ8ncA==|nu2sEvotjd4zusvGF8YZJPnS9SiJPDqc1VIfCrfve/o="
}
```

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

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

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

```http
PUT /bitwarden/api/folders/14220912-d002-471d-a364-a82a010cb8f2 HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```json
{
  "name": "2.d7MttWzJTSSKx1qXjHUxlQ==|01Ath5UqFZHk7csk5DVtkQ==|EMLoLREgCUP5Cu4HqIhcLqhiZHn+NsUDp8dAg1Xu0Io="
}
```

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

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

#### Response

```http
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

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

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

```http
POST /bitwarden/api/organizations HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```json
{
  "name": "Family",
  "key": "4.bmFjbF53D9mrdGbVqQzMB54uIg678EIpU/uHFYjynSPSA6vIv5/6nUy4Uk22SjIuDB3pZ679wLE3o7R/Imzn47OjfT6IrJ8HaysEhsZA25Dn8zwEtTMtgNepUtH084wAMgNeIcElW24U/MfRscjAk8cDUIm5xnzyi2vtJfe9PcHTmzRXyng=",
  "collectionName": "2.rrpSDDODsWZqL7EhLVsu/Q==|OSuh+MmmR89ppdb/A7KxBg==|kofpAocL2G4a3P1C2R1U+i9hWbhfKfsPKM6kfoyCg/M="
}
```

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

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

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

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

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

```http
DELETE /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```json
{
  "masterPasswordHash": "r5CFRR+n9NQI8a525FY+0BPR0HGOjVJX0cR1KEMnIOo="
}
```

#### Response

```http
HTTP/1.1 200 OK
```

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

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

#### Request

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

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

```http
POST /bitwarden/api/organizations/724db920-cc4b-0139-6ab2-543d7eb8149c/users/89d99af0db1c0139605b543d7eb8149c/confirm HTTP/1.1
Host: alice.example.com
Content-Type: application/json
```

```json
{
  "key": "4.UT/TVY6qmAjNdax2WT9JcA97wSWvEudAlqpjfxrFUieOoGA88MxzbYjpCXajEST/PehD1I7KC93jwthng772extu+lLHSd/Ce+a5Qw8+pRxL7je8QgS8gmP0FhfRLc4bl5hUMTfQcUDiuiiNaDez6E9czOzk9iuVaGpEjK4YAYgQy25m3eGc+DTPv8206NJZ/lr8CpPyhwUHjtDhlOZnDWAf+a28x2EAj1ogZKKJGAUcRENitV8Joa7OGRO6dmxtTTnWOuPDk5DajGgzpIQURNuotVHcpBtCL8HzNAduQ9vtrPKJtyAsHRdjau2SwEnaLZmxAvp7d9VG3t5nDYtgWA=="
}
```

#### Response

```http
HTTP/1.1 200 OK
```

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

This route gives the public key of a user.

#### Request

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

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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

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

#### Response

```http
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

```http
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

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

#### Response

```http
HTTP/1.1 200 OK
Content-Type: application/json
```

```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}`.