Workflow:OpenHands OpenHands Organization Onboarding
| Knowledge Sources | |
|---|---|
| Domains | Multi_Tenancy, Billing, Identity_Management |
| Last Updated | 2026-02-11 21:00 GMT |
Overview
End-to-end process for creating a new organization, provisioning LiteLLM resources, establishing billing relationships, and migrating existing users to the organization model.
Description
This workflow handles organization creation and user onboarding in the OpenHands enterprise platform. It uses a compensation pattern (saga) to coordinate between the internal database and external services (LiteLLM, Stripe). The process creates a LiteLLM team for API key management, persists the organization entity, establishes ownership, and handles rollback if any step fails. For existing users migrating to the organization model, a Redis-locked migration process transfers settings, billing, and credentials.
Usage
Execute this workflow when a new user signs up for OpenHands Cloud (automatic personal org creation), when an admin creates a new team organization, or when an existing pre-organization user needs to be migrated to the organization-based model.
Execution Steps
Step 1: Name Validation
Validate that the requested organization name is unique in the database. This is an early-fail check that requires no cleanup if it fails, as no external resources have been created yet.
Key considerations:
- Raises OrgNameExistsError if the name is already taken
- For personal orgs, the org ID is set equal to the user's UUID
Step 2: LiteLLM Team Provisioning
Create the external LiteLLM integration resources. This involves creating a team with budget allocation and allowed models, creating or finding a user record, adding the user to the team, and generating an API key for the team.
Provisioning sequence:
- POST /team/new: Create team with budget and models metadata
- POST /user/new: Create user (falls back to no-email if duplicate)
- Add user to team with budget allocation
- POST /key/generate: Create API key with alias "OpenHands Cloud - user {id} - org {id}"
Key considerations:
- LiteLLM resources are created BEFORE database persistence (external-first pattern)
- API key alias format enables auditing and debugging
- Authentication via x-goog-api-key header
Step 3: Organization Entity Creation
Create the in-memory organization entity with metadata including the LiteLLM settings. Transfer the API base URL, model configuration, and key information from the LiteLLM response to the organization object.
Key considerations:
- Org stores llm_model, llm_base_url, and llm_api_key from LiteLLM
- Default settings are applied for condenser, sandbox, and other preferences
- A unique UUID is generated for the org ID
Step 4: Ownership Establishment
Fetch the owner role from the database and create an OrgMember entity linking the creating user to the organization with owner permissions. The membership record includes role-based access control fields.
Key considerations:
- Role hierarchy: owner > admin > member
- OrgMember links user_id, org_id, and role_id
Step 5: Database Persistence with Compensation
Persist all entities (Org, OrgMember, User updates) to the database in a single transaction. If persistence fails, trigger the compensation pattern to clean up the already-created LiteLLM resources.
Compensation sequence on failure:
- Catch database exception
- Call LiteLLM delete_team to cascade-delete team, keys, and memberships
- Log cleanup result (best-effort, errors during cleanup are logged but not re-raised)
- Raise OrgDatabaseError with both the original and cleanup error details
Step 6: User Migration (Existing Users)
For pre-organization users, acquire a Redis distributed lock (30-second timeout) to prevent concurrent migrations. Create a personal organization, migrate LiteLLM entries (transferring budget and spend), migrate the Stripe customer relationship, decrypt legacy credentials, and update all related tables.
Tables updated during migration:
- stripe_customers: Associate with org
- slack_users, slack_conversation: Update org references
- api_keys, custom_secrets: Transfer to new org
- billing_sessions: Link to personal org
- conversation_metadata: Migrate to saas table
Key considerations:
- Redis lock key prevents race conditions during concurrent migration attempts
- BYOR (Bring Your Own Runtime) export flag is set based on billing history
- Billing margin adjustments are applied for users below version 4
Step 7: Post-Migration Verification
Verify the migration completed successfully by checking that the user's current_org_id points to their personal organization, LiteLLM entries are properly migrated (max_budget set to UNLIMITED), and all dependent table references are updated.
Key considerations:
- Already-migrated check: max_budget != None AND != UNLIMITED_BUDGET_SETTING
- UNLIMITED_BUDGET_SETTING = 1000000000.0