---
title: 'Troubleshooting: ScaiKey sync issues'
path: troubleshooting/scaikey-sync
status: published
---

# Troubleshooting: ScaiKey sync issues

## `403 Platform token requires admin:read or admin:write scope`

The credentials the backend is using don't have admin scope on ScaiKey, so it can't reach `applications.get_effective_users`.

**The sync falls back automatically** to a member-walk over `groups.list_members`. Slower (O(N_groups × N_members) instead of O(N_users)) but works with tenant-tier scopes.

Confirm the fallback kicked in: `POST /v1/admin/sync` and check `users_method` in the response. Should be `"member_walk"` (vs `"effective_users"` when admin scope is available).

**If you'd rather use the fast path:** re-issue your backend's ScaiKey credentials with `admin:read` and `admin:write` scopes. The `scaiflow scaikey-register` CLI does this in one shot.

## `groups_seen: 0` after sync

No groups were enumerated. Likely causes:

- The ScaiKey credentials don't have `groups:read` scope.
- The tenant genuinely has no groups (unusual).
- `groups.list` returns paginated results and the SDK pagination isn't completing — file a bug with the sync response.

**Fix:** Add `groups:read` to the credentials. Re-run sync.

## "Sync complete but no super_admin elected"

After a sync, the log warns:

```text
ScaiKey sync OK but no super_admin elected. Two ways to bootstrap:
  (manual)  apps/api/.venv/bin/scaiflow-admin grant <email> --role super_admin
  (group)   set SCAIFLOW_SUPER_ADMIN_GROUPS to a comma-separated list of group ids/names
```

Pick one:

- **Manual bootstrap:** Grant yourself via the admin CLI on the backend host. Survives all future syncs (`admin_role_source = manual`).
- **Group-derived:** Create a ScaiKey group named (or with id) `<your-admin-group>`, add yourself, set `SCAIFLOW_SUPER_ADMIN_GROUPS=<group_id_or_name>` on the backend, restart, sync. Members of that group auto-elevate.

The latter scales better across tenants — onboard new admins by adding them to the group in ScaiKey, no ScaiFlow ops needed.

## Webhooks not arriving

Symptoms: changes in ScaiKey (user joins, group memberships) take an hour to show up in ScaiFlow.

- Confirm `SCAIFLOW_SCAIKEY_WEBHOOK_SECRET` is set on the backend (unset → endpoint returns 503 fail-closed).
- Check the webhook configuration in ScaiKey points at the right URL: `https://scaiflow.example/api/v1/webhooks/scaikey`.
- Check the secret in ScaiKey matches `SCAIFLOW_SCAIKEY_WEBHOOK_SECRET`.
- Try `POST /v1/admin/sync` manually — if that works but webhooks don't, the issue is delivery, not handling.

ScaiKey doesn't reach `localhost`. In local dev, tunnel through ngrok / cloudflared, OR rely on the hourly background sync + manual `POST /v1/admin/sync` for testing.

## "User in ScaiKey but not in ScaiFlow"

`POST /v1/admin/sync` should pick up new users on the next run. If a specific user is missing after sync:

- They might not have ScaiFlow application assignment in ScaiKey (only users assigned to the ScaiFlow app appear in `effective_users`).
- For the member-walk fallback: they have to be in at least one group the ScaiKey credentials can see.

Confirm by listing users via `GET /v1/admin/users` and grep for the email.

## "I added myself to a super_admin group but I'm not super_admin"

`SCAIFLOW_SUPER_ADMIN_GROUPS` is only consulted at sync time. Trigger a sync to apply: `POST /v1/admin/sync`. The reconciliation step runs at the end of sync and promotes/demotes users based on group membership.

Manual grants (`admin_role_source = manual`) survive group reconciliation. So if you manually granted yourself super_admin and then later got added to a group, your `source` stays `manual`.
