---
title: "Suspend and reactivate a user"
description: "Deny new model requests before provider invocation and restore the same workspace access later."
---

> Documentation Index
> Fetch the complete documentation index at: https://nexus.microvoid.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Suspend and reactivate a user

## Goal

暂停一名应用用户的新请求，然后恢复同一条 WorkspaceAccess。

## Outcome

暂停期间的新请求返回 `workspace_access_denied`，并在调用 Provider 前结束；恢复后继续使用同一 Access、Plan、Period 和历史 Usage/Audit。

## Prerequisites

- Access ID、Management Key，以及该用户现有的 Gateway Base URL、Inference Key 和原始模型名。

## Lifecycle note

暂停是 Access 状态变化，不是删除用户、撤销所有历史事实或创建新 QuotaPeriod。Billing Connector 也只能异步投影这个状态，Gateway 不同步查询支付 Provider。

## 1. Exercise both state transitions

```js title="suspend-reactivate-access.mjs"
const adminBaseUrl = required('NEXUS_ADMIN_BASE_URL').replace(/\/$/, '');
const managementKey = required('NEXUS_MANAGEMENT_KEY');
const accessId = required('NEXUS_ACCESS_ID');
const gatewayBaseUrl = required('NEXUS_GATEWAY_BASE_URL').replace(/\/$/, '');
const inferenceKey = required('NEXUS_API_KEY');
const model = required('NEXUS_MODEL');

async function setAccess(action) {
  const response = await fetch(`${adminBaseUrl}/admin/v1/workspace-accesses/${accessId}/${action}`, {
    method: 'POST',
    headers: { Authorization: `Bearer ${managementKey}` },
  });
  if (!response.ok) throw new Error(`${action} failed: ${response.status} ${await response.text()}`);
  return response.json();
}

async function callModel() {
  return fetch(`${gatewayBaseUrl}/chat/completions`, {
    method: 'POST',
    headers: { Authorization: `Bearer ${inferenceKey}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({ model, messages: [{ role: 'user', content: 'Access state smoke test.' }] }),
  });
}

const suspended = await setAccess('suspend');
const denied = await callModel();
const deniedBody = await denied.json();
if (denied.status !== 403 || deniedBody.error?.code !== 'workspace_access_denied') {
  throw new Error(`expected workspace_access_denied, received ${denied.status}`);
}

const active = await setAccess('activate');
const restored = await callModel();
if (!restored.ok) throw new Error(`reactivated request failed: ${restored.status} ${await restored.text()}`);
console.log(
  JSON.stringify({
    suspended: suspended.status,
    active: active.status,
    requestId: restored.headers.get('x-nexus-request-id'),
  }),
);

function required(name) {
  const value = process.env[name]?.trim();
  if (!value) throw new Error(`${name} is required`);
  return value;
}
```

## Check your work

暂停响应为 `SUSPENDED`，恢复响应为 `ACTIVE`。暂停请求没有 Provider Attempt；恢复请求有新的 Invocation，之前的 UsageEvent 与 Audit Log 仍可查询。

## Failure modes

- `invalid_inference_key`：凭证本身不可用，与 Access 暂停不同。
- 恢复后仍拒绝：检查 `accessEndsAt`、当前 QuotaPeriod、ProviderConnection 状态和 Quota。
- Billing 状态很快再次覆盖：先确认 Billing Connector 的订阅投影事实，而不是在 Gateway 加例外。

## Security notes

暂停不会泄露用户是否属于其他 Workspace。不要通过删除审计/用量记录来“完成”暂停。

## Next steps

用 [Troubleshooting](/cookbook/troubleshooting) 判断错误发生在哪一层。

Source: https://nexus.microvoid.io/cookbook/suspend-reactivate-access/index.mdx
