Skip to content
You are reading the HappyView v2 docs, which are no longer updated. Read the v3 docs.

Users

Manage admin users and their permissions. See the Permissions guide for available permissions and templates.

const TOKEN = "hv_..."; // your API key
const headers = { Authorization: `Bearer ${TOKEN}` };
POST /admin/users

Requires users:create permission. You cannot grant permissions you don’t have yourself (escalation guard).

interface User {
id: string;
did: string;
is_super: boolean;
permissions: string[];
}
const response = await fetch("http://127.0.0.1:3000/admin/users", {
method: "POST",
headers: {
...headers,
"Content-Type": "application/json",
},
body: JSON.stringify({
did: "did:plc:newuser",
template: "operator",
}),
});
const data: User = await response.json();
FieldTypeRequiredDescription
didstringyesThe atproto DID of the user to add
templatestringnoPermission template: viewer, operator, manager, or full_access
permissionsstring[]noExplicit list of permissions to grant (used instead of or in addition to template)

If neither template nor permissions is provided, the user is created with no permissions.

Response: 201 Created

{
"id": "550e8400-e29b-41d4-a716-446655440000",
"did": "did:plc:newuser",
"is_super": false,
"permissions": ["lexicons:read", "records:read", "script-variables:read", "users:read", "api-keys:read", "api-keys:create", "api-keys:delete", "backfill:read", "backfill:create", "stats:read", "events:read"]
}
GET /admin/users

Requires users:read permission.

interface UserWithTimestamps {
id: string;
did: string;
is_super: boolean;
permissions: string[];
created_at: string;
last_used_at: string;
}
const response = await fetch("http://127.0.0.1:3000/admin/users", {
headers,
});
const data: UserWithTimestamps[] = await response.json();

Response: 200 OK

[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"did": "did:plc:admin",
"is_super": true,
"permissions": ["lexicons:create", "lexicons:read", "lexicons:delete", "records:read", "records:delete", "records:delete-collection", "script-variables:create", "script-variables:read", "script-variables:delete", "users:create", "users:read", "users:update", "users:delete", "api-keys:create", "api-keys:read", "api-keys:delete", "backfill:create", "backfill:read", "stats:read", "events:read"],
"created_at": "2025-01-01T00:00:00Z",
"last_used_at": "2025-01-02T12:00:00Z"
}
]
GET /admin/users/{id}

Requires users:read permission.

const response = await fetch(
"http://127.0.0.1:3000/admin/users/550e8400-e29b-41d4-a716-446655440000",
{ headers },
);
const data: UserWithTimestamps = await response.json();

Response: 200 OK with the same shape as a single item from the list response.

PATCH /admin/users/{id}/permissions

Requires users:update permission. You cannot grant permissions you don’t have yourself, and you cannot modify the super user’s permissions.

const response = await fetch(
"http://127.0.0.1:3000/admin/users/550e8400-e29b-41d4-a716-446655440000/permissions",
{
method: "PATCH",
headers: {
...headers,
"Content-Type": "application/json",
},
body: JSON.stringify({
grant: ["lexicons:create", "lexicons:delete"],
revoke: ["records:delete"],
}),
},
);
const data: User = await response.json();
FieldTypeRequiredDescription
grantstring[]noPermissions to add
revokestring[]noPermissions to remove

Response: 200 OK with the updated user object.

POST /admin/users/transfer-super

Only the current super user can call this endpoint. Transfers super user status to another existing user.

const response = await fetch("http://127.0.0.1:3000/admin/users/transfer-super", {
method: "POST",
headers: {
...headers,
"Content-Type": "application/json",
},
body: JSON.stringify({
target_user_id: "550e8400-e29b-41d4-a716-446655440000",
}),
});
FieldTypeRequiredDescription
target_user_idstringyesThe ID of the user to receive super status

Response: 200 OK

DELETE /admin/users/{id}

Requires users:delete permission. You cannot delete the super user or yourself.

const response = await fetch(
"http://127.0.0.1:3000/admin/users/550e8400-e29b-41d4-a716-446655440000",
{
method: "DELETE",
headers,
},
);

Response: 204 No Content