---
title: "Admin API"
description: "Verified `/api/admin/*` routes for user management, moderation, store ops, platform settings, and Email CRM"
locale: "en"
---
# Admin API

> **Info**
> Filter with **Founder** / **Developer** in the docs sidebar. Legacy copy claimed **12 endpoints**, fabricated `GET /api/admin/users` list/search, `GET /api/admin/analytics`, IP whitelisting, and admin-only rate limits — **none verified in this tree**. Below matches `app/api/admin/**/route.ts` as of v1.6.4.

Admin routes power the **Admin console** (`/admin/*`): user roles, entity moderation, verification desk, store order status, platform branding/AI settings, ProcessConductor pipelines, Web3 desk tools, and Email AI-CRM. All browser calls use **Auth.js session cookies** on the same origin — see [API reference](/docs/api.md).

## Access tiers

| Guard | Roles | Typical routes |
|-------|-------|----------------|
| `isPlatformAdmin()` | `admin`, `superadmin` | Users, orders, moderation, verification queue |
| `isSuperadmin()` / `requireSuperadminApi()` | `superadmin` only | Platform settings, processes, Web3 desk, branding save |
| Service-layer checks | Admin in domain service | Entity moderation queue, verification actions |
| `requireEmailAdmin()` | Platform admin + email CRM | `/api/admin/email/*` |

SSOT: `features/auth/user-role.ts` — lowercase roles (`visitor` … `superadmin`).

### For founders

## What operators control via Admin API

These HTTP handlers back buttons in the admin UI — you rarely call them manually unless automating ops.

  
- **[Admin console](/docs/features/admin.md)** — Role-aware three-pane nav, Security hub tabs, Email CRM shell — UI SSOT for these APIs.

  
- **[User desk](/docs/features/admin.md)** — View one user, change role, manual verification badge, delete account (not self), Payments tab (membership + wallet top-up ledger).

  
- **[Trust & safety](/docs/features/admin.md)** — Security hub (fraud / verification / events), entity moderation queue, KYC procedures.

  
- **[Store ERP](/docs/features/store.md)** — Advance order status: `new` → `paid` → `processing` → `shipped` → `completed` / `canceled`.

  
- **[Email AI-CRM](/docs/api/email-ai-crm.md)** — Threads, drafts, tasks, analytics — separate admin email namespace.

  
- **[Platform analytics](/docs/deployment/monitoring.md)** — Dashboard at `/admin/analytics` — not a monolithic `/api/admin/analytics` route.

### Typical operator scenarios

- **Inspect payments** — Admin → Users → Eye → Payments tab loads `GET /api/admin/users/{id}/payments` (`membership_upgrade` + `wallet_topup` from `payment_transactions`).
- **Promote a member to confidential** — admin UI → `PUT /api/admin/users/{id}/role` or legacy `POST /api/admin/set-user-role`.
- **Clear verification backlog** — `/admin/security?tab=verification` (legacy `/admin/verification` redirects here) → `POST /api/admin/verification/procedures/{n}/{action}` (`approve`, `reject`, `request-info`, `under-review`).
- **Pause an abusive entity** — moderation queue → `POST /api/admin/entity-moderation/block` with `entityId` + `reason`.
- **Rebrand clone colors** — superadmin settings form → `POST /api/admin/whitelabel/save` (redirects to admin settings).
- **Set RING/USD oracle rate** — Web3 desk → `POST /api/admin/web3/settings` with `{ "nativePerMainCurrency": "..." }`; persisted in `platform_settings` `web3` namespace.

> **Warning**
> **Superadmin-only** changes (AI keys, branding JSON, manual pipeline runs, RING oracle rate) affect every user — restrict `superadmin` role count on production clones.

### For developers

## Auth pattern

```mermaid
sequenceDiagram
  participant C as Client (cookie)
  participant R as /api/admin/*
  participant A as auth()
  participant S as Domain service

  C->>R: fetch credentials include
  R->>A: session
  alt not platform admin
    R-->>C: 401 / 403
  else authorized
    R->>S: Zod-validated body
    S-->>R: result
    R-->>C: JSON
```

{`curl -s "http://localhost:3000/api/admin/entity-moderation" \\
  -H "Cookie: authjs.session-token=YOUR_SESSION_COOKIE" | jq .`}

There is **no** verified global admin rate-limit middleware in `app/api/admin/*`. Add edge rate limits in your reverse proxy if needed.

## Route inventory (verified)

### Users & roles

| Method | Path | Auth | Notes |
|--------|------|------|-------|
| GET | `/api/admin/users/[id]` | Platform admin | Single user JSONB doc; passwords stripped |
| GET | `/api/admin/users/[id]/payments` | Platform admin | Ledger rows via `paymentTransactionService.listByUserId` — default purposes `membership_upgrade`, `wallet_topup`; query `?limit=` (max 100), `?purposes=a,b` |
| DELETE | `/api/admin/users/[id]` | Platform admin | Cannot delete self |
| PUT | `/api/admin/users/[id]/role` | Platform admin | Body: `{ "role": "member" }` |
| PUT | `/api/admin/users/[id]/verification` | Admin manual verification | Body: `{ "isVerified": true, ... }` |
| POST | `/api/admin/set-user-role` | Platform admin | Legacy: `{ "uid", "role" }`; blocks admin self-demotion |

**Not implemented:** `GET /api/admin/users` list/search — use Admin UI server loaders or `DatabaseService` in custom tooling.

**Payments tab UI:** `features/auth/components/admin-user-detail-sheet.tsx` (opened from `admin-user-manager.tsx` Eye button) fetches `/api/admin/users/${user.id}/payments?limit=50`.

### Native payment refunds

| Method | Path | Auth | Notes |
|--------|------|------|-------|
| POST | `/api/admin/payments/[orderReference]/refund` | Platform admin **or** owning vendor | Body `{ "reason" }`; native_token paid rows only; full-amount, idempotent (already-refunded replays `refundTxHash`); treasury→user via `transferTokenFromTreasury`; row status `refunded` + `refundTxHash` in `processor_payload`; transfer failure keeps row `paid` (retryable). Vendor gate: order `vendorSettlements` must match one of the caller's `getVendorEntities`. |

### Moderation & verification

| Method | Path | Notes |
|--------|------|-------|
| GET | `/api/admin/entity-moderation` | `{ items: EntityModerationQueueItem[] }` |
| POST | `/api/admin/entity-moderation/block` | `{ entityId, reason }` |
| GET | `/api/admin/verification/queue` | `{ success, queue }` |
| POST | `/api/admin/verification/procedures/[procedureNumber]/[action]` | `approve` \| `reject` \| `request-info` \| `under-review` |

### Store

| Method | Path | Body |
|--------|------|------|
| POST | `/api/admin/orders/[id]/status` | `{ "status": "processing" }` — enum: `new`, `paid`, `processing`, `shipped`, `completed`, `canceled` |

### Platform settings (superadmin)

| Method | Path | Notes |
|--------|------|-------|
| GET | `/api/admin/platform-settings?namespace=ai\|branding` | Read namespace |
| PUT | `/api/admin/platform-settings` | JSON body: `{ namespace, data, secrets? }` |
| POST | `/api/admin/whitelabel/save` | Form POST → branding colors → redirect |
| POST | `/api/admin/save` | Legacy branding save (JSON redirect) |

**Persistence (verified):** `features/admin/platform-settings/platform-settings-service.ts` reads and writes the `platform_settings` collection through `db()` from `@/lib/database` — not a private `pg.Pool`. Namespaces `ai` and `branding` use `readDoc` / `updateDoc` / `createDoc` with in-process namespace cache (`platform-settings-cache.ts`).

| Env | Effect |
|-----|--------|
| `PLATFORM_SETTINGS_DISABLE_DB=true` | Reads return defaults / null; **writes throw** — use for CI or env-only clones |

`importPlatformSettingsFromEnv()` seeds `ai` and `branding` from env + `ring-config.json` on first boot when DB rows are missing.

### ProcessConductor (superadmin)

| Method | Path | Notes |
|--------|------|-------|
| GET | `/api/admin/processes` | Lists pipelines |
| POST | `/api/admin/processes/[id]/run` | Manual pipeline trigger |
| GET | `/api/admin/processes/[id]/history` | Run history |

Cron equivalents use `/api/cron/*` + `CRON_SECRET` — see ProcessConductor docs in [Monitoring](/docs/deployment/monitoring.md).

### Web3 desk (superadmin)

| Method | Path | Notes |
|--------|------|-------|
| GET | `/api/admin/web3/settings` | Oracle rate, desk config, audit log, gas reserve |
| POST | `/api/admin/web3/settings` | `{ "nativePerMainCurrency": "..." }` |
| GET | `/api/admin/web3/gas-reserve` | Solana fee-payer balance |

**Oracle persistence:** `features/wallet/services/native-token-oracle.ts` stores `nativePerMainCurrency` and audit rows in `platform_settings` doc id `web3` via the same `db()` API. When `PLATFORM_SETTINGS_DISABLE_DB=true`, reads fall back to `RING_ORACLE_DEFAULT_RATE` (or `100`) and writes are blocked.

### Email AI-CRM (platform admin)

Full route table: **[Email AI-CRM API](/docs/api/email-ai-crm.md)** — threads, drafts, tasks, contacts, `GET /api/admin/email/analytics?range=7d`.

### Maintenance (superadmin, use with care)

| Method | Path | Purpose |
|--------|------|---------|
| POST | `/api/admin/migrate-users` | One-off user migration helper — not for routine ops |

## Analytics (not under `/api/admin`)

| Method | Path | Auth |
|--------|------|------|
| GET | `/api/analytics/platform-stats` | Platform admin |
| GET | `/api/analytics/web-vitals?scope=platform` | Platform admin |
| GET | `/api/analytics/errors` | Platform admin |

UI: `/admin/analytics` → `getPlatformAnalytics()` (`features/analytics/services/get-platform-analytics.ts`).

### Example — change role

### Authenticate as admin in browser

Sign in with an `admin` or `superadmin` account.

### PUT role

{`curl -X PUT "http://localhost:3000/api/admin/users/USER_ID/role" \\
  -H "Content-Type: application/json" \\
  -H "Cookie: authjs.session-token=..." \\
  -d '{"role":"confidential"}'`}

### Verify

Re-fetch user or open Admin → Users; role is lowercase in `users.data.role`.

## Related documentation

  
- **[API index](/docs/api.md)** — Session auth model and domain map.

  
- **[Email AI-CRM API](/docs/api/email-ai-crm.md)** — All `/api/admin/email/*` routes.

  
- **[Security model](/docs/architecture/security.md)** — RBAC layers and confidential tiers.

  
- **[Monitoring](/docs/deployment/monitoring.md)** — Admin analytics and error ingest.

  
- **[Wallet API — oracle](/docs/api/wallet.md)** — Member-facing desk quotes; admin rate via Web3 desk above.
