Summary and recommendation
Bitwarden's Public API uses OAuth 2.0 client credentials (scope: api.organization) issued per organization from the web vault. The token endpoint (https://identity.bitwarden.com/connect/token) and the API base URL (https://api.bitwarden.com) are separate hosts - a common misconfiguration point. Access tokens expire; implement refresh logic on 401 responses rather than assuming token longevity.
Self-hosted deployments replace both URLs with custom domain equivalents, so any integration must make base URLs configurable. Bitwarden does not publish numeric rate limits; no rate-limit headers are returned, so implement conservative retry logic with exponential backoff.
API quick reference
| Has user API | Yes |
| Auth method | OAuth 2.0 client credentials (organization API key) |
| Base URL | Official docs |
| SCIM available | Yes |
| SCIM plan required | Teams or Enterprise |
Authentication
Auth method: OAuth 2.0 client credentials (organization API key)
Setup steps
- Log in to the Bitwarden web vault as an organization owner.
- Navigate to Organization Settings > My Organization.
- Scroll to API Key section and click View API Key.
- Note the client_id (format: organization.{uuid}) and client_secret.
- POST to https://identity.bitwarden.com/connect/token with grant_type=client_credentials, scope=api.organization, client_id, and client_secret.
- Use the returned access_token as a Bearer token in the Authorization header for all Public API requests.
Required scopes
| Scope | Description | Required for |
|---|---|---|
| api.organization | Grants access to the Bitwarden Public API for organization management operations. | All Public API endpoints including member, group, collection, and event management. |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | string (UUID) | Unique identifier for the organization member. | system-generated | read-only | Used as path parameter for member operations. |
| userId | string (UUID) | Bitwarden user account UUID. | system-generated | read-only | Distinct from the organization membership id. |
| string | User's email address. | required | not updatable via API | Used to invite members. | |
| name | string | Display name of the user. | optional | read-only | Set by the user on their account. |
| status | integer (enum) | Membership status: 0=Invited, 1=Accepted, 2=Confirmed, -1=Revoked. | auto-set to 0 | via confirm/revoke endpoints | Revoked members retain their account but lose org access. |
| type | integer (enum) | Organization role: 0=Owner, 1=Admin, 2=User, 3=Manager, 4=Custom. | required | updatable | Custom role requires Enterprise plan. |
| accessAll | boolean | Whether the member has access to all collections. | optional | updatable | If true, collections array is ignored. |
| externalId | string | External identifier for directory sync. | optional | updatable | Used by Directory Connector and SCIM. |
| resetPasswordEnrolled | boolean | Whether the member is enrolled in admin password reset. | read-only | read-only | Enrollment is user-initiated or policy-enforced. |
| collections | array of objects | Collections the member has access to, with readOnly and hidePasswords flags. | optional | updatable | Ignored if accessAll is true. |
| groups | array of strings (UUIDs) | Group IDs the member belongs to. | optional | updatable via group endpoints | Groups available on Teams and Enterprise plans. |
| twoFactorEnabled | boolean | Whether the user has two-step login enabled. | read-only | read-only | Informational only. |
| permissions | object | Granular permissions for Custom role members. | optional | updatable | Only applicable when type=4 (Custom). |
Core endpoints
List organization members
- Method: GET
- URL:
https://api.bitwarden.com/public/members - Watch out for: Returns all members regardless of status (invited, accepted, confirmed, revoked). No pagination; all members returned in one response.
Request example
GET /public/members
Authorization: Bearer {access_token}
Response example
{
"data": [
{"id":"uuid","email":"user@example.com","status":2,"type":2,"accessAll":false}
],
"object": "list"
}
Get a member
- Method: GET
- URL:
https://api.bitwarden.com/public/members/{id} - Watch out for: The {id} is the organization membership UUID, not the user's global Bitwarden userId.
Request example
GET /public/members/member-uuid
Authorization: Bearer {access_token}
Response example
{
"id": "member-uuid",
"email": "user@example.com",
"status": 2,
"type": 2,
"accessAll": false,
"object": "member"
}
Invite a member
- Method: POST
- URL:
https://api.bitwarden.com/public/members - Watch out for: Invitation email is sent automatically. Member status is 0 (Invited) until they accept. Cannot invite an email already in the organization.
Request example
POST /public/members
Content-Type: application/json
{
"email": "newuser@example.com",
"type": 2,
"accessAll": false,
"collections": [{"id":"col-uuid","readOnly":false}]
}
Response example
{
"id": "new-member-uuid",
"email": "newuser@example.com",
"status": 0,
"type": 2,
"object": "member"
}
Update a member
- Method: PUT
- URL:
https://api.bitwarden.com/public/members/{id} - Watch out for: Full replacement (PUT), not partial update. Omitting fields may reset them. Use GET first to preserve existing values.
Request example
PUT /public/members/member-uuid
Content-Type: application/json
{
"type": 1,
"accessAll": true,
"collections": []
}
Response example
{
"id": "member-uuid",
"type": 1,
"accessAll": true,
"status": 2,
"object": "member"
}
Delete (remove) a member
- Method: DELETE
- URL:
https://api.bitwarden.com/public/members/{id} - Watch out for: Permanently removes the member from the organization. Their personal Bitwarden account is not deleted. Consider using revoke instead to preserve audit history.
Request example
DELETE /public/members/member-uuid
Authorization: Bearer {access_token}
Response example
HTTP 200 OK (empty body)
Revoke a member
- Method: PUT
- URL:
https://api.bitwarden.com/public/members/{id}/revoke - Watch out for: Sets member status to -1 (Revoked). Member loses org access but remains in the member list. Can be restored via the restore endpoint.
Request example
PUT /public/members/member-uuid/revoke
Authorization: Bearer {access_token}
Response example
HTTP 200 OK (empty body)
Restore a member
- Method: PUT
- URL:
https://api.bitwarden.com/public/members/{id}/restore - Watch out for: Restores a previously revoked member. Member must re-confirm if they had not previously confirmed.
Request example
PUT /public/members/member-uuid/restore
Authorization: Bearer {access_token}
Response example
HTTP 200 OK (empty body)
List groups
- Method: GET
- URL:
https://api.bitwarden.com/public/groups - Watch out for: Groups are only available on Teams and Enterprise plans. Returns 404 or empty on Free/Families plans.
Request example
GET /public/groups
Authorization: Bearer {access_token}
Response example
{
"data": [
{"id":"group-uuid","name":"Engineering","accessAll":false}
],
"object": "list"
}
Rate limits, pagination, and events
Rate limits: Bitwarden does not publish explicit numeric rate limits for the Public API in official documentation.
Rate-limit headers: No
Retry-After header: No
Rate-limit notes: No documented rate limit tiers or headers found in official docs. Standard fair-use limits likely apply server-side.
Pagination method: none
Default page size: 0
Max page size: 0
Pagination pointer: Not documented
Webhooks available: No
Webhook notes: Bitwarden does not offer outbound webhooks from the Public API. Event logs are available via the /public/events endpoint (GET, poll-based).
Alternative event strategy: Poll GET https://api.bitwarden.com/public/events with date range filters (start, end query params) to retrieve audit events including user actions.
SCIM API status
SCIM available: Yes
SCIM version: 2.0
Plan required: Teams or Enterprise
Supported operations: GET /Users, GET /Users/{id}, POST /Users, PUT /Users/{id}, PATCH /Users/{id}, DELETE /Users/{id}, GET /Groups, GET /Groups/{id}, POST /Groups, PUT /Groups/{id}, PATCH /Groups/{id}, DELETE /Groups/{id}
Limitations:
- SCIM token is generated in Organization Settings > SCIM Provisioning; it is a static bearer token, not OAuth.
- SSO (Login with SSO) must be configured and enabled before SCIM provisioning is activated.
- Self-hosted Bitwarden uses a different SCIM endpoint: https://{your-domain}/scim/{organizationId}/v2.
- Deprovisioning via SCIM DELETE revokes the member (status=-1), it does not delete their Bitwarden account.
- Supported IdPs with native SCIM connectors: Okta, Azure AD (Entra ID), OneLogin, JumpCloud, Ping Identity.
- Google Workspace does not have a native SCIM connector; use Bitwarden Directory Connector instead.
- SCIM and Directory Connector should not be used simultaneously for the same organization.
Common scenarios
The Public API covers member invite, update (PUT, full replacement only), revoke, restore, and delete - plus group and collection management on Teams and Enterprise. The critical gap: member confirmation after acceptance cannot be automated via the Public API and requires a vault admin action.
For fully automated provisioning, SCIM is the correct path - it bypasses the confirmation step entirely and auto-confirms provisioned users.
Stitchflow connects to Bitwarden through an MCP server with ~100 deep IT/identity integrations, enabling provisioning workflows to be orchestrated across Bitwarden and adjacent systems - IdP, HRIS, ticketing - without building point-to-point API logic for each.
For event data, Bitwarden has no outbound webhooks; poll GET /public/events with start and end date filters to retrieve audit events.
Invite and confirm a new organization member
- Obtain an access token: POST https://identity.bitwarden.com/connect/token with client_id, client_secret, grant_type=client_credentials, scope=api.organization.
- Invite the user: POST https://api.bitwarden.com/public/members with {email, type, accessAll, collections}. Response returns member with status=0 (Invited).
- User receives invitation email and accepts it (status becomes 1=Accepted). This step is user-driven and cannot be automated via API.
- Confirm the member via the Bitwarden web vault (Admin Console > Members > Confirm). Note: there is no Public API endpoint to programmatically confirm a member; confirmation requires a vault action.
Watch out for: Member confirmation cannot be automated via the Public API - it requires a vault admin action. SCIM provisioning bypasses this limitation by auto-confirming provisioned users.
Deprovision a member when they leave the organization
- Obtain access token via client credentials flow.
- List members: GET https://api.bitwarden.com/public/members to find the member's organization membership id by email.
- Revoke the member: PUT https://api.bitwarden.com/public/members/{id}/revoke. This sets status=-1 and removes org access immediately.
- Optionally, permanently remove: DELETE https://api.bitwarden.com/public/members/{id} if you do not need to restore them later.
Watch out for: Revoke is reversible; DELETE is permanent. Neither action deletes the user's personal Bitwarden account or their personal vault data.
Set up SCIM provisioning with Okta
- Ensure the organization is on Teams or Enterprise plan.
- Configure Login with SSO in Bitwarden Admin Console (SSO must be active before enabling SCIM).
- In Bitwarden Admin Console, go to Settings > SCIM Provisioning, enable SCIM, and copy the SCIM URL and API token.
- In Okta, add the Bitwarden application from the Okta Integration Network.
- In the Bitwarden Okta app, navigate to Provisioning > Integration, enter the SCIM base URL (https://scim.bitwarden.com/{orgId}/v2) and the SCIM token as the API token.
- Enable provisioning features: Push New Users, Push Profile Updates, Push Groups, Deactivate Users.
- Assign users/groups in Okta; Bitwarden will auto-provision and confirm them via SCIM.
Watch out for: The SCIM token is a static long-lived token - rotate it in Bitwarden Admin Console if compromised. Okta SCIM DELETE maps to Bitwarden member revocation, not account deletion.
Why building this yourself is a trap
PUT /members/{id} is a full replacement - omitting any field (collections, permissions, accessAll) silently resets it. Always GET the current member state before any update. The member {id} in the Public API is the organization membership UUID, not the user's global Bitwarden userId - using the wrong identifier returns a 404 with no descriptive error.
SCIM requires SSO to be configured and active before provisioning is enabled; enabling SCIM without SSO produces provisioning errors that surface in the IdP, not in Bitwarden. The SCIM token is a static long-lived bearer token with no rotation schedule enforced by Bitwarden, so token hygiene is entirely the operator's responsibility.
Groups and SCIM endpoints return errors or empty results on plans below Teams; plan-gate your API calls accordingly.
Automate Bitwarden workflows without one-off scripts
Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.