Skip to main content

Overview

The Sync endpoint is the primary method for retrieving all vault data in a single request. It returns:
  • User profile information
  • All ciphers (vault items)
  • Folders
  • Collections
  • Organizations
  • Policies
  • Sends
  • Encryption keys
Clients should call this endpoint periodically to keep vault data synchronized. Use the revision date to detect changes.

Sync Vault Data

Retrieve all vault data for the authenticated user.
GET /sync?excludeDomains={excludeDomains}
excludeDomains
boolean
default:"false"
Exclude equivalent domain data from response to reduce payload size
curl -X GET "https://api.bitwarden.com/sync" \
  -H "Authorization: Bearer {access_token}"

Response Structure

User Profile

profile
object
required
User account information
profile.id
string
required
User ID
profile.name
string
User’s display name
profile.email
string
required
User’s email address
profile.twoFactorEnabled
boolean
required
Whether 2FA is enabled
profile.premium
boolean
required
Whether user has premium
profile.organizations
array
User’s organization memberships
profile.providers
array
User’s provider memberships

Vault Data

folders
object
required
User’s folders with data array
collections
object
required
Organization collections accessible to user
ciphers
object
required
All vault items (passwords, notes, cards, identities)
sends
object
Bitwarden Send items

Organization Data

policies
object
Organization policies that apply to user

Encryption

domains
object
Equivalent domain data (excluded if excludeDomains=true)

Response Format

Each data section follows this structure:
{
  "object": "list",
  "data": [
    // Array of items
  ],
  "continuationToken": null
}

Full Response Example

{
  "profile": {
    "id": "user-guid",
    "name": "John Doe",
    "email": "[email protected]",
    "emailVerified": true,
    "premium": true,
    "twoFactorEnabled": true,
    "key": "encrypted-key-data",
    "privateKey": "encrypted-private-key",
    "securityStamp": "stamp-value",
    "organizations": [
      {
        "id": "org-guid",
        "name": "My Organization",
        "useGroups": true,
        "useDirectory": true,
        "useTotp": true,
        "seats": 10,
        "type": 0,
        "status": 2,
        "permissions": {}
      }
    ]
  },
  "folders": {
    "object": "list",
    "data": [
      {
        "id": "folder-guid",
        "name": "2.encrypted_name",
        "revisionDate": "2024-01-01T00:00:00Z"
      }
    ]
  },
  "collections": {
    "object": "list",
    "data": [
      {
        "id": "collection-guid",
        "organizationId": "org-guid",
        "name": "2.encrypted_name",
        "externalId": null,
        "readOnly": false,
        "hidePasswords": false,
        "manage": false
      }
    ]
  },
  "ciphers": {
    "object": "list",
    "data": [
      {
        "id": "cipher-guid",
        "type": 1,
        "name": "2.encrypted_name",
        "notes": "2.encrypted_notes",
        "login": {
          "username": "2.encrypted_username",
          "password": "2.encrypted_password",
          "totp": "2.encrypted_totp",
          "uris": [
            {"uri": "2.encrypted_uri"}
          ]
        },
        "favorite": false,
        "organizationId": null,
        "collectionIds": [],
        "revisionDate": "2024-01-01T00:00:00Z"
      }
    ]
  },
  "sends": {
    "object": "list",
    "data": []
  },
  "policies": {
    "object": "list",
    "data": []
  },
  "domains": {
    "equivalentDomains": [],
    "globalEquivalentDomains": []
  }
}

Sync Strategy

Full Sync

Perform a full sync when:
  • User logs in
  • App starts after being closed
  • User manually triggers refresh

Incremental Sync

Use revision dates to detect changes:
  1. Store last sync revisionDate locally
  2. Call GET /accounts/revision-date to check for updates
  3. If revision date changed, perform full sync
  4. Update stored revision date
const lastSync = localStorage.getItem('lastSyncDate');
const revisionDate = await fetch('/accounts/revision-date', {
  headers: { 'Authorization': `Bearer ${token}` }
}).then(r => r.json());

if (revisionDate > lastSync) {
  // Perform full sync
  const syncData = await fetch('/sync');
  localStorage.setItem('lastSyncDate', revisionDate);
}

Background Sync

Recommended intervals:
  • Active use: Every 5-10 minutes
  • Background: Every 30 minutes
  • On network change: Immediate sync

Performance Optimization

Reduce Payload Size

  1. Use excludeDomains=true if you don’t need equivalent domains
  2. Filter SSH keys on older clients using client version checks
  3. Compress responses with gzip/brotli encoding

Caching Strategy

// Cache sync data with revision tracking
const syncCache = {
  data: null,
  revisionDate: null,
  
  async fetch(token) {
    const currentRevision = await this.getRevisionDate(token);
    
    if (this.data && this.revisionDate === currentRevision) {
      return this.data; // Return cached data
    }
    
    // Fetch fresh data
    this.data = await fetch('/sync', {
      headers: { 'Authorization': `Bearer ${token}` }
    }).then(r => r.json());
    
    this.revisionDate = currentRevision;
    return this.data;
  },
  
  async getRevisionDate(token) {
    return fetch('/accounts/revision-date', {
      headers: { 'Authorization': `Bearer ${token}` }
    }).then(r => r.json());
  }
};

Error Handling

401 Unauthorized
Access token expired or invalid - trigger re-authentication
403 Forbidden
User account locked or disabled
500 Server Error
Server error - implement exponential backoff retry

Retry Strategy

async function syncWithRetry(token, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fetch('/sync', {
        headers: { 'Authorization': `Bearer ${token}` }
      }).then(r => r.json());
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
    }
  }
}

WebSocket Events

For real-time sync, subscribe to WebSocket notifications:
const ws = new WebSocket('wss://notifications.bitwarden.com');

ws.on('message', async (event) => {
  const data = JSON.parse(event.data);
  
  if (data.type === 'SyncCipherUpdate') {
    // Trigger sync
    await performSync();
  }
});
WebSocket notifications are recommended for active sessions to receive instant updates when vault data changes.

Build docs developers (and LLMs) love