Admin (Multi-tenant)
July 25, 2026 ยท View on GitHub
The Admin API manages accounts and users in a multi-tenant environment. It covers workspace (account) creation/deletion, user registration/removal, role changes, and API key regeneration.
This API is available in both api_key and trusted deployments:
- In
api_keymode, the effective role is always derived from the presented API key. - In
trustedmode, ordinary requests still do not use user-key registration. When a configuredroot_api_keyis presented to/api/v1/admin/*, the trusted upstream is authorized as ROOT.
For /api/v1/admin/*, trusted mode permits requests with no explicit identity headers, and also permits target identity headers when they match the account/user in the URL. These requests are treated as ROOT after the deployment's root_api_key is verified. For ordinary trusted-mode data APIs, role and identity still come from X-OpenViking-Account + X-OpenViking-User.
Roles and Permissions
| Role | Description |
|---|---|
| ROOT | System administrator with full access |
| ADMIN | Workspace administrator, manages users within their account |
| USER | Regular user |
| Operation | ROOT | ADMIN | USER |
|---|---|---|---|
| Create/delete workspace | Y | N | N |
| List workspaces | Y | N | N |
| Register/remove users | Y | Y (own account) | N |
| List agents (deprecated, returns empty list) | Y | Y (own account) | N |
| Regenerate user key | Y | Y (own account) | N |
| Change user role | Y | N | N |
CLI --sudo Option
When using the ov CLI to perform admin operations requiring ROOT privileges, you can use the --sudo option. This option uses the root_api_key from your ~/.openviking/ovcli.conf instead of the regular api_key.
Configuration Requirements
Configure root_api_key in ~/.openviking/ovcli.conf:
{
"url": "http://localhost:1933",
"api_key": "alice-user-key",
"root_api_key": "your-root-api-key",
...
}
Commands Supporting --sudo
ov --sudo admin- Account and user managementov --sudo system- System utility commandsov --sudo reindex- Rebuild indexesov --sudo admin migrate- Legacy agent/session migration and cleanupov --sudo task status/list- Query root/system background tasks, such as migration tasks
Usage Limitations
--sudoonly works with the commands above - using it with regular data commands will error- Must have
root_api_keyconfigured to use--sudo
API Reference
create_account
1. API Implementation Overview
Create a new workspace with its first admin user.
Processing Flow:
- Verify requester has ROOT privileges
- Use API Key Manager to create account and initial admin user
- Initialize account-level directory structure
- Initialize admin user's personal directory
- Write optional initial admin user config
- Return account info and user key (not in trusted mode)
Code Entry Points:
openviking/server/routers/admin.py:create_account- HTTP routeopenviking/server/api_keys/new.py:APIKeyManager.create_account- Core implementationopenviking_cli/client/sync_http.py:SyncHTTPClient.admin_create_account- Python SDK
2. Interface and Parameters
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| account_id | str | Yes | - | Workspace ID |
| admin_user_id | str | Yes | - | First admin user ID |
| seed | str | No | null | Optional deterministic API key seed. When set, the key secret is sha256(user_id + "\0" + seed) |
| user_config | object | No | null | Initial config for the first admin user. Currently supports add_targets.resource_uri and add_targets.skill_uri |
Notes:
- In
trustedmode,user_keyis omitted from the response - Omit
seedfor the default random API key. Treat seed values as secret material; short seeds can make the key guessable. - Account-level namespace isolation settings are no longer supported. User memory uses user-scoped namespaces, and one-to-many external participants are represented with
peer_id. user_config.add_targets.resource_urimust be a writable resource directory URI:viking://resourcesorviking://resources/...,viking://user/resourcesorviking://user/resources/...,viking://user/{user_id}/resourcesorviking://user/{user_id}/resources/..., orviking://user/{user_id}/peers/{peer_id}/resourcesorviking://user/{user_id}/peers/{peer_id}/resources/....user_config.add_targets.skill_urimust beviking://user/skillsorviking://agent/skills. Explicitviking://user/{user_id}/skillsis not accepted in v1.
3. Usage Examples
HTTP API
POST /api/v1/admin/accounts
curl -X POST http://localhost:1933/api/v1/admin/accounts \
-H "Content-Type: application/json" \
-H "X-API-Key: <root-key>" \
-d '{
"account_id": "acme",
"admin_user_id": "alice",
"seed": "alice-seed"
}'
Trusted mode (registered gateway user)
# First, register the gateway admin user in api_key mode
curl -X POST http://localhost:1933/api/v1/admin/accounts \
-H "Content-Type: application/json" \
-H "X-API-Key: <root-key>" \
-d '{
"account_id": "platform",
"admin_user_id": "gateway-admin"
}'
# Then promote it to root for cross-account admin operations
curl -X PUT http://localhost:1933/api/v1/admin/accounts/platform/users/gateway-admin/role \
-H "Content-Type: application/json" \
-H "X-API-Key: <root-key>" \
-d '{"role": "root"}'
# Then use in trusted mode
curl -X POST http://localhost:1933/api/v1/admin/accounts \
-H "Content-Type: application/json" \
-H "X-API-Key: <root-key>" \
-H "X-OpenViking-Account: platform" \
-H "X-OpenViking-User: gateway-admin" \
-d '{
"account_id": "acme",
"admin_user_id": "alice"
}'
Trusted mode (root fallback without identity headers)
curl -X POST http://localhost:1933/api/v1/admin/accounts \
-H "Content-Type: application/json" \
-H "X-API-Key: <root-key>" \
-d '{
"account_id": "acme",
"admin_user_id": "alice"
}'
Python SDK
import openviking as ov
client = ov.SyncHTTPClient(api_key="<root-key>")
client.initialize()
result = client.admin_create_account("acme", "alice", seed="alice-seed")
print(f"Account created: {result['account_id']}")
print(f"Admin user: {result['admin_user_id']}")
print(f"User key: {result.get('user_key', '(not exposed in trusted mode)')}")
result = client.admin_create_account(
"acme-private",
"alice",
user_config={
"add_targets": {
"resource_uri": "viking://user/resources",
"skill_uri": "viking://user/skills",
}
},
)
TypeScript SDK
console.log(await client.adminCreateAccount("account-id", "admin-user-id"));
Go SDK
result, err := client.AdminCreateAccount(ctx, "acme", "alice")
if err != nil {
return err
}
fmt.Println(result["account_id"])
seed := "alice-seed"
result, err = client.AdminCreateAccountWithOptions(ctx, "acme-private", "alice", &openviking.AdminCreateAccountOptions{
Seed: &seed,
UserConfig: map[string]any{
"add_targets": map[string]any{
"resource_uri": "viking://user/resources",
"skill_uri": "viking://user/skills",
},
},
})
CLI
# Requires ROOT privileges, use --sudo
ov --sudo admin create-account acme --admin alice
ov --sudo admin create-account acme --admin alice --seed alice-seed
ov --sudo admin create-account acme-private --admin alice \
--user-config-json '{"add_targets":{"resource_uri":"viking://user/resources","skill_uri":"viking://user/skills"}}'
Response Example
{
"status": "ok",
"result": {
"account_id": "acme",
"admin_user_id": "alice",
"user_key": "7f3a9c1e..."
},
"time": 0.1
}
In trusted mode, the same response omits user_key.
list_accounts
1. API Implementation Overview
List all workspaces (ROOT only).
Processing Flow:
- Verify requester has ROOT privileges
- Call API Key Manager to get all accounts
- Return list with account ID, creation time, and user count
Code Entry Points:
openviking/server/routers/admin.py:list_accounts- HTTP routeopenviking/server/api_keys/new.py:APIKeyManager.get_accounts- Core implementationopenviking_cli/client/sync_http.py:SyncHTTPClient.admin_list_accounts- Python SDK
2. Interface and Parameters
No parameters.
3. Usage Examples
HTTP API
GET /api/v1/admin/accounts
curl -X GET http://localhost:1933/api/v1/admin/accounts \
-H "X-API-Key: <root-key>"
Python SDK
import openviking as ov
client = ov.SyncHTTPClient(api_key="<root-key>")
client.initialize()
accounts = client.admin_list_accounts()
for account in accounts:
print(f"Account: {account['account_id']}, created: {account['created_at']}, users: {account['user_count']}")
TypeScript SDK
console.log(await client.adminListAccounts());
Go SDK
accounts, err := client.AdminListAccounts(ctx)
if err != nil {
return err
}
fmt.Println(accounts)
CLI
# Requires ROOT privileges, use --sudo
ov --sudo admin list-accounts
Response Example
{
"status": "ok",
"result": [
{"account_id": "default", "created_at": "2026-02-12T10:00:00Z", "user_count": 1},
{"account_id": "acme", "created_at": "2026-02-13T08:00:00Z", "user_count": 2}
],
"time": 0.1
}
delete_account
1. API Implementation Overview
Delete a workspace and all associated users and data (ROOT only).
Processing Flow:
- Verify requester has ROOT privileges
- Cascade delete all AGFS data for the account (
user/andresources/; sessions live underuser/) - Cascade delete all vector DB records for the account
- Finally delete account metadata and all user keys
Code Entry Points:
openviking/server/routers/admin.py:delete_account- HTTP routeopenviking/server/api_keys/new.py:APIKeyManager.delete_account- Core implementationopenviking_cli/client/sync_http.py:SyncHTTPClient.admin_delete_account- Python SDK
2. Interface and Parameters
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| account_id | str | Yes | - | Workspace ID to delete |
Notes:
- Delete operation is irreversible and cascades to all account data
- If some data fails to delete, warnings are logged and deletion continues
3. Usage Examples
HTTP API
DELETE /api/v1/admin/accounts/{account_id}
curl -X DELETE http://localhost:1933/api/v1/admin/accounts/acme \
-H "X-API-Key: <root-key>"
Python SDK
import openviking as ov
client = ov.SyncHTTPClient(api_key="<root-key>")
client.initialize()
result = client.admin_delete_account("acme")
print(f"Account deleted: {result['deleted']}")
TypeScript SDK
await client.adminDeleteAccount("account-id");
Go SDK
result, err := client.AdminDeleteAccount(ctx, "acme")
if err != nil {
return err
}
fmt.Println(result["deleted"])
CLI
# Requires ROOT privileges, use --sudo
ov --sudo admin delete-account acme
Response Example
{
"status": "ok",
"result": {
"deleted": true
},
"time": 0.1
}
register_user
1. API Implementation Overview
Register a new user in a workspace.
Processing Flow:
- Verify requester has ROOT privileges or is an ADMIN of the account
- Call API Key Manager to register new user
- Initialize new user's personal directory
- Write optional initial user config
- Return user info and user key (not in trusted mode)
Code Entry Points:
openviking/server/routers/admin.py:register_user- HTTP routeopenviking/server/api_keys/new.py:APIKeyManager.register_user- Core implementationopenviking_cli/client/sync_http.py:SyncHTTPClient.admin_register_user- Python SDK
2. Interface and Parameters
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| account_id | str | Yes | - | Workspace ID |
| user_id | str | Yes | - | User ID |
| role | str | No | "user" | Role to assign. ROOT and same-account ADMIN may register "user" or "admin". "root" must be assigned through the dedicated role-change endpoint. |
| seed | str | No | null | Optional deterministic API key seed. When set, the key secret is sha256(user_id + "\0" + seed) |
| user_config | object | No | null | Initial config for the new user. Currently supports add_targets.resource_uri and add_targets.skill_uri |
Notes:
- In
trustedmode,user_keyis omitted from the response - Omit
seedfor the default random API key. Treat seed values as secret material; short seeds can make the key guessable. - ADMIN can only register users in their own account
- The
"root"role cannot be minted through user registration user_config.add_targets.resource_urimust be a writable resource directory URI:viking://resourcesorviking://resources/...,viking://user/resourcesorviking://user/resources/...,viking://user/{user_id}/resourcesorviking://user/{user_id}/resources/..., orviking://user/{user_id}/peers/{peer_id}/resourcesorviking://user/{user_id}/peers/{peer_id}/resources/....user_config.add_targets.skill_urimust beviking://user/skillsorviking://agent/skills. Explicitviking://user/{user_id}/skillsis not accepted in v1.
3. Usage Examples
HTTP API
POST /api/v1/admin/accounts/{account_id}/users
curl -X POST http://localhost:1933/api/v1/admin/accounts/acme/users \
-H "Content-Type: application/json" \
-H "X-API-Key: <root-or-admin-key>" \
-d '{
"user_id": "bob",
"role": "user",
"seed": "bob-seed"
}'
Python SDK
import openviking as ov
client = ov.SyncHTTPClient(api_key="<root-or-admin-key>")
client.initialize()
result = client.admin_register_user("acme", "bob", role="user", seed="bob-seed")
print(f"User registered: {result['user_id']}")
print(f"User key: {result.get('user_key', '(not exposed in trusted mode)')}")
result = client.admin_register_user(
"acme",
"bob-private",
role="user",
user_config={"add_targets": {"resource_uri": "viking://user/resources/project-a"}},
)
TypeScript SDK
console.log(await client.adminRegisterUser("account-id", "user-id", "user"));
Go SDK
result, err := client.AdminRegisterUser(ctx, "acme", "bob", "user")
if err != nil {
return err
}
fmt.Println(result["user_id"])
seed := "bob-seed"
result, err = client.AdminRegisterUserWithOptions(ctx, "acme", "bob-private", "user", &openviking.AdminRegisterUserOptions{
Seed: &seed,
UserConfig: map[string]any{
"add_targets": map[string]any{"resource_uri": "viking://user/resources/project-a"},
},
})
CLI
# Either ROOT or account ADMIN can execute
# If using regular user's api_key who is an ADMIN of acme:
ov admin register-user acme bob --role user
ov admin register-user acme bob --role user --seed bob-seed
# If using root_api_key (--sudo):
ov --sudo admin register-user acme bob --role user
ov admin register-user acme bob-private --role user \
--user-config-json '{"add_targets":{"resource_uri":"viking://user/resources/project-a"}}'
Response Example
{
"status": "ok",
"result": {
"account_id": "acme",
"user_id": "bob",
"user_key": "d91f5b2a..."
},
"time": 0.1
}
list_users
1. API Implementation Overview
List all users in a workspace.
Processing Flow:
- Verify requester has ROOT privileges or is an ADMIN of the account
- Call API Key Manager to get users list
- Apply optional filters (name, role) and pagination limit
- Return users list (trusted mode omits user_key)
Code Entry Points:
openviking/server/routers/admin.py:list_users- HTTP routeopenviking/server/api_keys/new.py:APIKeyManager.get_users- Core implementationopenviking_cli/client/sync_http.py:SyncHTTPClient.admin_list_users- Python SDK
2. Interface and Parameters
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| account_id | str | Yes | - | Workspace ID |
| limit | int | No | 100 | Maximum number of users to return |
| name | str | No | null | Filter by user ID (prefix match) |
| role | str | No | null | Filter by role |
Notes:
- ADMIN can only list users in their own account
- In
trustedmode,user_keyis omitted from the response
3. Usage Examples
HTTP API
GET /api/v1/admin/accounts/{account_id}/users
# List all users
curl -X GET http://localhost:1933/api/v1/admin/accounts/acme/users \
-H "X-API-Key: <root-or-admin-key>"
# With filters
curl -X GET "http://localhost:1933/api/v1/admin/accounts/acme/users?role=admin&limit=50" \
-H "X-API-Key: <root-or-admin-key>"
Python SDK
import openviking as ov
client = ov.SyncHTTPClient(api_key="<root-or-admin-key>")
client.initialize()
users = client.admin_list_users("acme")
for user in users:
print(f"User: {user['user_id']}, role: {user['role']}")
TypeScript SDK
console.log(await client.adminListUsers("account-id"));
Go SDK
users, err := client.AdminListUsers(ctx, "acme")
if err != nil {
return err
}
fmt.Println(users)
CLI
# Either ROOT or account ADMIN can execute
# If using regular user's api_key who is an ADMIN of acme:
ov admin list-users acme
# If using root_api_key (--sudo):
ov --sudo admin list-users acme
Response Example
{
"status": "ok",
"result": [
{"user_id": "alice", "role": "admin"},
{"user_id": "bob", "role": "user"}
],
"time": 0.1
}
remove_user
1. API Implementation Overview
Remove a user from a workspace. The user's API key is deleted immediately.
Processing Flow:
- Verify requester has ROOT privileges or is an ADMIN of the account
- Call API Key Manager to delete user and their API key
- Return deletion confirmation
Code Entry Points:
openviking/server/routers/admin.py:remove_user- HTTP routeopenviking/server/api_keys/new.py:APIKeyManager.remove_user- Core implementationopenviking_cli/client/sync_http.py:SyncHTTPClient.admin_remove_user- Python SDK
2. Interface and Parameters
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| account_id | str | Yes | - | Workspace ID |
| user_id | str | Yes | - | User ID to remove |
Notes:
- ADMIN can only remove users in their own account
- Cannot delete the last admin user of an account
3. Usage Examples
HTTP API
DELETE /api/v1/admin/accounts/{account_id}/users/{user_id}
curl -X DELETE http://localhost:1933/api/v1/admin/accounts/acme/users/bob \
-H "X-API-Key: <root-or-admin-key>"
Python SDK
import openviking as ov
client = ov.SyncHTTPClient(api_key="<root-or-admin-key>")
client.initialize()
result = client.admin_remove_user("acme", "bob")
print(f"User deleted: {result['deleted']}")
TypeScript SDK
await client.adminRemoveUser("account-id", "user-id");
Go SDK
result, err := client.AdminRemoveUser(ctx, "acme", "bob")
if err != nil {
return err
}
fmt.Println(result["deleted"])
CLI
# Either ROOT or account ADMIN can execute
# If using regular user's api_key who is an ADMIN of acme:
ov admin remove-user acme bob
# If using root_api_key (--sudo):
ov --sudo admin remove-user acme bob
Response Example
{
"status": "ok",
"result": {
"deleted": true
},
"time": 0.1
}
set_role
1. API Implementation Overview
Change a user's role (ROOT only).
Processing Flow:
- Verify requester has ROOT privileges
- Call API Key Manager to update user role
- Return updated user info
Code Entry Points:
openviking/server/routers/admin.py:set_user_role- HTTP routeopenviking/server/api_keys/new.py:APIKeyManager.set_role- Core implementationopenviking_cli/client/sync_http.py:SyncHTTPClient.admin_set_role- Python SDK
2. Interface and Parameters
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| account_id | str | Yes | - | Workspace ID |
| user_id | str | Yes | - | User ID |
| role | str | Yes | - | New role: "admin", "user", or "root" |
Notes:
- Only ROOT can change user roles
- Role can be set to "admin", "user", or "root"
3. Usage Examples
HTTP API
PUT /api/v1/admin/accounts/{account_id}/users/{user_id}/role
curl -X PUT http://localhost:1933/api/v1/admin/accounts/acme/users/bob/role \
-H "Content-Type: application/json" \
-H "X-API-Key: <root-key>" \
-d '{"role": "admin"}'
Python SDK
import openviking as ov
client = ov.SyncHTTPClient(api_key="<root-key>")
client.initialize()
result = client.admin_set_role("acme", "bob", "admin")
print(f"User: {result['user_id']}, new role: {result['role']}")
TypeScript SDK
await client.adminSetRole("account-id", "user-id", "admin");
Go SDK
result, err := client.AdminSetRole(ctx, "acme", "bob", "admin")
if err != nil {
return err
}
fmt.Println(result["role"])
CLI
# Requires ROOT privileges, use --sudo
ov --sudo admin set-role acme bob admin
Response Example
{
"status": "ok",
"result": {
"account_id": "acme",
"user_id": "bob",
"role": "admin"
},
"time": 0.1
}
regenerate_key
1. API Implementation Overview
Regenerate a user's API key. The old key is immediately invalidated.
Processing Flow:
- Verify requester has ROOT privileges or is an ADMIN of the account
- Call API Key Manager to regenerate user key
- Old key is immediately invalidated
- Return new user key
Code Entry Points:
openviking/server/routers/admin.py:regenerate_key- HTTP routeopenviking/server/api_keys/new.py:APIKeyManager.regenerate_key- Core implementationopenviking_cli/client/sync_http.py:SyncHTTPClient.admin_regenerate_key- Python SDK
2. Interface and Parameters
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| account_id | str | Yes | - | Workspace ID |
| user_id | str | Yes | - | User ID |
| seed | str | No | null | Optional deterministic API key seed in the JSON request body. When set, the key secret is sha256(user_id + "\0" + seed) |
Notes:
- ADMIN can only regenerate keys for users in their own account
- Old key is immediately invalidated, clients using it need to be updated
- Omit
seedfor the default random regenerated key.
3. Usage Examples
HTTP API
POST /api/v1/admin/accounts/{account_id}/users/{user_id}/key
curl -X POST http://localhost:1933/api/v1/admin/accounts/acme/users/bob/key \
-H "Content-Type: application/json" \
-H "X-API-Key: <root-or-admin-key>" \
-d '{"seed": "bob-new-seed"}'
Python SDK
import openviking as ov
client = ov.SyncHTTPClient(api_key="<root-or-admin-key>")
client.initialize()
result = client.admin_regenerate_key("acme", "bob", seed="bob-new-seed")
print(f"New user key: {result['user_key']}")
TypeScript SDK
console.log(await client.adminRegenerateKey("account-id", "user-id"));
Go SDK
result, err := client.AdminRegenerateKey(ctx, "acme", "bob")
if err != nil {
return err
}
fmt.Println(result["user_key"])
seed := "bob-new-seed"
result, err = client.AdminRegenerateKeyWithOptions(ctx, "acme", "bob", &openviking.AdminRegenerateKeyOptions{
Seed: &seed,
})
CLI
# Either ROOT or account ADMIN can execute
# If using regular user's api_key who is an ADMIN of acme:
ov admin regenerate-key acme bob
ov admin regenerate-key acme bob --seed bob-new-seed
# If using root_api_key (--sudo):
ov --sudo admin regenerate-key acme bob
Response Example
{
"status": "ok",
"result": {
"user_key": "e82d4e0f..."
},
"time": 0.1
}
migrate_legacy_data
1. API Implementation Overview
Migrate 0.3.x legacy viking://agent/... / viking://session/... data into the 0.4.0 user / peer namespace, or clean up old namespaces after migration has been verified. This endpoint is ROOT-only and runs as a background task.
Processing Flow:
- Verify requester has ROOT privileges
- For
action=migrate, run preflight checks for account registry, session owner metadata, and other prerequisites - Create a root-level background task
- During migration, copy files and existing vector records; during cleanup, delete old vector records before deleting old AGFS directories
Migration does not automatically call reindex. If retrieval after migration is not as expected, users should manually reindex the new paths.
Code Entry Points:
openviking/server/routers/admin.py:migrate_legacy_data- HTTP routeopenviking/service/legacy_migration.py:LegacyDataMigration- Migration implementation
2. Interface and Parameters
HTTP API
POST /api/v1/admin/migrate
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| action | str | No | migrate | migrate runs migration; cleanup removes old namespaces |
Migration result fields
| Field | Description |
|---|---|
| migrated.files / migrated.directories | Number of files and directories copied |
| migrated.vector_records | Number of existing vector records copied |
| migrated.skipped_vector_records | Number of old records skipped because they had no vector payload |
| migrated.operations | Operation counts grouped by migration category |
| skipped / warnings / created_users | Skipped items, warnings, and users created automatically |
Cleanup result fields
| Field | Description |
|---|---|
| cleanup.directories | Number of legacy directories deleted |
| cleanup.vector_records | Number of old vector records deleted |
| cleanup.targets | Legacy scopes that were cleaned |
| skipped / warnings | Skipped items and warnings |
3. Usage Examples
HTTP API
# Run migration
curl -X POST http://localhost:1933/api/v1/admin/migrate \
-H "Content-Type: application/json" \
-H "X-API-Key: <root-key>" \
-d '{"action": "migrate"}'
# Clean old namespaces
curl -X POST http://localhost:1933/api/v1/admin/migrate \
-H "Content-Type: application/json" \
-H "X-API-Key: <root-key>" \
-d '{"action": "cleanup"}'
Python SDK
print(client.admin_migrate(cleanup=False))
TypeScript SDK
console.log(await client.adminMigrate(false));
Go SDK
result, err := client.AdminMigrate(ctx, &openviking.AdminMigrateOptions{
Cleanup: false,
})
if err != nil {
return err
}
fmt.Println(result["task_id"])
CLI
ov --sudo admin migrate --output json
ov --sudo admin migrate --cleanup --output json
Response Example
{
"task_id": "legacy_migration_..."
}
Full Example
Typical Admin Workflow
# Step 1: ROOT creates workspace with alice as first admin (requires --sudo)
ov --sudo admin create-account acme --admin alice
# Returns alice's user_key
# Step 2: alice (admin) registers regular user bob
# Configure api_key in config file to alice's user_key, no --sudo needed
ov admin register-user acme bob --role user
# Returns bob's user_key
# Step 3: List all users in the account
ov admin list-users acme
# Step 4: ROOT promotes bob to admin (requires --sudo)
ov --sudo admin set-role acme bob admin
# Step 5: bob lost their key, regenerate (old key immediately invalidated)
# alice as admin can do this, no --sudo needed
ov admin regenerate-key acme bob
# Step 6: Remove user
ov admin remove-user acme bob
# Step 7: Delete entire workspace (requires --sudo)
ov --sudo admin delete-account acme
HTTP API Equivalent
# Step 1: Create workspace
curl -X POST http://localhost:1933/api/v1/admin/accounts \
-H "Content-Type: application/json" \
-H "X-API-Key: <root-key>" \
-d '{"account_id": "acme", "admin_user_id": "alice"}'
# Step 2: Register user (using alice's admin key)
curl -X POST http://localhost:1933/api/v1/admin/accounts/acme/users \
-H "Content-Type: application/json" \
-H "X-API-Key: <alice-key>" \
-d '{"user_id": "bob", "role": "user"}'
# Step 3: List users
curl -X GET http://localhost:1933/api/v1/admin/accounts/acme/users \
-H "X-API-Key: <alice-key>"
# Step 4: Change role (requires ROOT key)
curl -X PUT http://localhost:1933/api/v1/admin/accounts/acme/users/bob/role \
-H "Content-Type: application/json" \
-H "X-API-Key: <root-key>" \
-d '{"role": "admin"}'
# Step 5: Regenerate key
curl -X POST http://localhost:1933/api/v1/admin/accounts/acme/users/bob/key \
-H "Content-Type: application/json" \
-H "X-API-Key: <alice-key>"
# Step 6: Remove user
curl -X DELETE http://localhost:1933/api/v1/admin/accounts/acme/users/bob \
-H "X-API-Key: <alice-key>"
# Step 7: Delete workspace
curl -X DELETE http://localhost:1933/api/v1/admin/accounts/acme \
-H "X-API-Key: <root-key>"
Related Documentation
- Multi-Tenant - Tenant model, roles, and sharing boundaries
- API Overview - Authentication and response format
- Sessions - Session management
- System - System and monitoring API