---
title: 'REST API: Admin'
path: reference/rest-api/admin
status: published
---

# REST API: Admin

ScaiKey-driven user/group sync, super_admin role management, tenant admin views.

All endpoints under `/api/v1/admin`. Most require `super_admin` (`role` is the ScaiFlow-local admin role, not a ScaiKey role); a few `/tenant/*` endpoints accept `tenant_admin` too.

## `GET /v1/admin/users`

List every user mirrored from ScaiKey.

Super admin only.

**Response:**

```jsonc
{
  "users": [
    {
      "id": "usr_xxx",
      "tenant_id": "tnt_acme",
      "email": "alice@acme.example",
      "display_name": "Alice Johnson",
      "status": "ACTIVE",
      "admin_role": "tenant_admin",       // null | tenant_admin | super_admin
      "admin_role_source": "manual",      // null | manual | group | bootstrap
      "deleted_at": null,
      "last_synced_at": "2026-04-29..."
    }
  ]
}
```

## `POST /v1/admin/sync`

Trigger an immediate sync from ScaiKey. Same code path as the hourly background sync.

Super admin only.

**Response:**

```jsonc
{
  "skipped_reason": null,
  "users_method": "effective_users",     // or "member_walk" (fallback path)
  "users_seen": 42,
  "users_added": 3,
  "users_undeleted": 0,
  "users_soft_deleted": 1,
  "groups_seen": 7,
  "groups_added": 0,
  "groups_undeleted": 0,
  "groups_soft_deleted": 0,
  "memberships_seen": 86,
  "memberships_added": 5,
  "memberships_soft_deleted": 2,
  "super_admin_count": 2,
  "super_admins_group_promoted": 0,
  "super_admins_group_demoted": 0,
  "duration_seconds": 1.8
}
```

`skipped_reason` is set when sync was skipped (e.g. `credentials_missing` — `SCAIKEY_BASE_URL` etc. not configured).

`users_method` indicates which path mirrored users: `effective_users` (preferred, platform-tier ScaiKey credentials) or `member_walk` (tenant-tier fallback).

## `POST /v1/admin/users/{user_id}/role`

Grant an admin role to a user.

**Body:**

```jsonc
{ "role": "tenant_admin" }   // or "super_admin"
```

Super admin can grant either role to anyone. Tenant admin can grant `tenant_admin` to users in their own tenant only.

`204 No Content`.

The grant is recorded with `admin_role_source = "manual"` — survives reconciliation (the group-derived sync won't demote a manual grant). Use the matching DELETE to revoke.

## `DELETE /v1/admin/users/{user_id}/role`

Revoke an admin role. Same permission rules as grant.

`204 No Content`.

Refuses to demote the last super_admin (would lock out platform access). Set another super_admin first.

## `GET /v1/admin/tenant/users`

All users in the calling tenant. Accepts tenant_admin (sees own tenant only) or super_admin (sees specified or own tenant).

**Query:**

- `tenant_id` — (super_admin only) view a different tenant's users.

**Response:** same shape as `/v1/admin/users` but scoped.

## `GET /v1/admin/tenant/flows`

All flows in the calling tenant, regardless of per-flow ACLs (tenant admins have implicit `admin` access on every flow in their tenant).

**Response:**

```jsonc
[
  {
    "id": "flow_xxx",
    "name": "Customer Support",
    "owner_id": "usr_alice",
    "owner_email": "alice@acme.example",
    "version": "1.0.2",
    "created_at": "2026-04-01...",
    "updated_at": "2026-04-29..."
  }
]
```

Used by the tenant admin UI to surface every flow in the tenant, even ones the admin doesn't have an explicit ACL on.
