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
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 判断错误发生在哪一层。