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
Navigate to Organization Settings
Go to Settings > Organization Info
Generate an API Key
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.
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
Code Meaning Description 200 OK Request successful 201 Created Resource created 400 Bad Request Invalid request data 401 Unauthorized Invalid or missing token 403 Forbidden Insufficient permissions 404 Not Found Resource doesn’t exist 429 Too Many Requests Rate limit exceeded 500 Server Error Internal server error
Best Practices
Authentication
Rotate API keys regularly (every 90 days recommended)
Store credentials securely - never commit to version control
Use environment variables for API credentials
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
Implement exponential backoff for retries
Cache responses when appropriate
Batch operations where possible
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