Skip to main content

What is the Public API?

The Bitwarden Public API is designed for organization administrators to manage their organization programmatically. It provides endpoints for:
  • Managing organization members
  • Organizing groups
  • Configuring policies
  • Bulk operations
The Public API is separate from the standard API and requires organization-scoped authentication.

Authentication

Public API endpoints use organization-scoped OAuth tokens with the Organization policy:
Authorization: Bearer {organization_api_token}

Getting an API Key

  1. Navigate to Organization Settings
  2. Go to Settings > Organization Info
  3. Generate an API Key
  4. Use client_id and client_secret to obtain access tokens

OAuth Token Request

curl -X POST "https://identity.bitwarden.com/connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "scope=api.organization" \
  -d "client_id={organization.client_id}" \
  -d "client_secret={organization.client_secret}"

Response

{
  "access_token": "eyJhbGci...",
  "expires_in": 3600,
  "token_type": "Bearer",
  "scope": "api.organization"
}

Base URL

All Public API endpoints are prefixed with /public:
https://api.bitwarden.com/public

API Endpoints

Members

  • GET /public/members - List organization members
  • GET /public/members/{id} - Get member details
  • POST /public/members - Invite new member
  • PUT /public/members/{id} - Update member
  • DELETE /public/members/{id} - Remove member

Groups

  • GET /public/groups - List groups
  • GET /public/groups/{id} - Get group details
  • POST /public/groups - Create group
  • PUT /public/groups/{id} - Update group
  • DELETE /public/groups/{id} - Delete group

Policies

  • GET /public/policies - List policies
  • GET /public/policies/{id} - Get policy details
  • PUT /public/policies/{id} - Update policy

Rate Limiting

The Public API implements rate limiting to ensure fair usage:
  • Rate: 100 requests per minute per organization
  • Burst: Up to 20 requests in quick succession
Rate limit headers are included in responses:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640000000
Exceeding rate limits returns 429 Too Many Requests. Implement exponential backoff in your code.

Response Format

Success Response

Successful requests return JSON with the requested data:
{
  "id": "member-guid",
  "email": "[email protected]",
  "name": "John Doe",
  "type": 2,
  "status": 2
}

List Response

List endpoints return paginated data:
{
  "object": "list",
  "data": [
    {...},
    {...}
  ],
  "continuationToken": null
}

Error Response

Errors return appropriate HTTP status codes with details:
{
  "object": "error",
  "message": "The request is invalid.",
  "validationErrors": {
    "Email": ["Email is required."]
  }
}

Common HTTP Status Codes

CodeMeaningDescription
200OKRequest successful
201CreatedResource created
400Bad RequestInvalid request data
401UnauthorizedInvalid or missing token
403ForbiddenInsufficient permissions
404Not FoundResource doesn’t exist
429Too Many RequestsRate limit exceeded
500Server ErrorInternal server error

Best Practices

Authentication

  1. Rotate API keys regularly (every 90 days recommended)
  2. Store credentials securely - never commit to version control
  3. Use environment variables for API credentials
  4. Implement token caching - reuse tokens until expiration

Error Handling

async function callPublicAPI(endpoint) {
  try {
    const response = await fetch(`https://api.bitwarden.com/public${endpoint}`, {
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      }
    });
    
    if (response.status === 429) {
      // Rate limited - wait and retry
      const resetTime = response.headers.get('X-RateLimit-Reset');
      await sleep(resetTime - Date.now());
      return callPublicAPI(endpoint);
    }
    
    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.message);
    }
    
    return await response.json();
  } catch (error) {
    console.error('API Error:', error);
    throw error;
  }
}

Rate Limiting

  1. Implement exponential backoff for retries
  2. Cache responses when appropriate
  3. Batch operations where possible
  4. Monitor rate limit headers to avoid hitting limits

Use Cases

SCIM/Directory Sync

Automate user provisioning from your identity provider:
import requests

def sync_users(users, org_api_token):
    headers = {"Authorization": f"Bearer {org_api_token}"}
    
    for user in users:
        # Check if user exists
        members = requests.get(
            "https://api.bitwarden.com/public/members",
            headers=headers
        ).json()
        
        existing = next(
            (m for m in members['data'] if m['email'] == user['email']),
            None
        )
        
        if not existing:
            # Invite new member
            requests.post(
                "https://api.bitwarden.com/public/members",
                headers=headers,
                json={
                    "email": user['email'],
                    "type": 2,
                    "accessAll": False,
                    "collections": []
                }
            )

Automated Onboarding

Invite new team members during onboarding:
#!/bin/bash

# Invite new employee
curl -X POST "https://api.bitwarden.com/public/members" \
  -H "Authorization: Bearer $ORG_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "type": 2,
    "collections": [
      {
        "id": "'$TEAM_COLLECTION_ID'",
        "readOnly": false
      }
    ],
    "groups": ["'$TEAM_GROUP_ID'"]
  }'

Compliance Reporting

Generate reports on organization membership:
const members = await fetch('https://api.bitwarden.com/public/members', {
  headers: { 'Authorization': `Bearer ${token}` }
}).then(r => r.json());

const report = {
  total: members.data.length,
  confirmed: members.data.filter(m => m.status === 2).length,
  pending: members.data.filter(m => m.status === 0).length,
  twoFactorEnabled: members.data.filter(m => m.twoFactorEnabled).length
};

console.log('Organization Report:', report);

Next Steps

Members API

Manage organization members

Groups API

Organize users into groups

Policies API

Configure security policies

Build docs developers (and LLMs) love