ChatGPT 账号一键“下车”:教你用脚本自动清理所有关联空间
很多玩 AI 的朋友应该都遇到过这种情况:为了贪图免费额度或者一时手滑,把学校提供的 K12 教育版空间(Workspace)绑定到了自己的个人大号上。结果就是账号环境变得极其“脏”,不仅功能受限,看着也不舒服。更重要的是,很多过期的或被停用的空间,在界面上根本没有退出按钮,想删都删不掉,挂在列表里极其碍眼。
最近看到有开发者改写了一个超实用的 JS 脚本,专门解决这个问题。它不需要你安装任何软件,直接在浏览器控制台运行,就能批量把当前账号关联的所有空间“踢”出去。下面我就把这个“一键下车”的教程和原理解析一下。
⚠️ 核心原理:利用官方 DELETE API
其实官方并没有提供“一键退出所有空间”的界面按钮,但在后端 API 层面是支持操作的。这个脚本的核心逻辑就是:
- 获取当前会话 Token:先拿到你登录状态的 AccessToken。
- 遍历账号列表:调用
/backend-api/accounts/check接口,获取当前账号绑定的所有空间 ID 列表。 - 发送删除请求:循环遍历这些 ID,向
/backend-api/accounts/{account_id}/users/{user_id}发送DELETE请求。
只要请求返回 200,你就成功从该空间“下车”了。
🔧 使用教程:只需三步
第一步:准备环境 打开 ChatGPT 官网,确认你已经登录需要清理的那个“大号”。建议在操作前先切换到你的主个人账户(Personal),因为如果你正在某个受限空间的会话中,直接跑脚本可能会导致 Token 失效(401 错误)。
第二步:打开控制台
在网页上按 F12(或者右键点击“检查”),切换到 Console(控制台)标签页。
第三步:粘贴并运行 将下面的完整代码复制,粘贴到控制台的输入框里,按回车键执行。
(async function runrunrun() {
try {
// 1. 获取基础会话信息
const session = await fetch('/api/auth/session').then((r) => r.json());
const accessToken = session?.accessToken;
const user_id = session?.user?.id;
if (!accessToken || !user_id) {
console.log('获取 Token 或用户 ID 失败,请确认登录状态。');
return;
}
// 2. 获取账号列表
console.log('正在获取账号列表...');
const checkResponse = await fetch(
'https://chatgpt.com/backend-api/accounts/check/v4-2023-04-27?timezone_offset_min=-480',
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
}
);
if (!checkResponse.ok) {
console.log(`无法获取账号列表,HTTP 状态码: ${checkResponse.status}`);
return;
}
const checkData = await checkResponse.json();
const accountOrdering = checkData?.account_ordering || [];
if (accountOrdering.length === 0) {
console.log('未检测到可处理的账号列表。');
return;
}
console.log(`获取成功,共检测到 ${accountOrdering.length} 个账号。开始处理...`);
const results = { success: [], failed: [] };
// 3. 循环发送 DELETE 请求
for (const account_id of accountOrdering) {
try {
const response = await fetch(
`https://chatgpt.com/backend-api/accounts/${account_id}/users/${user_id}`,
{
method: 'DELETE',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
}
);
let responseText = '';
try { responseText = await response.text(); } catch (e) {}
let isSuccess = false;
if (response.status === 200) {
try {
const data = JSON.parse(responseText);
if (data?.success) {
isSuccess = true;
results.success.push(account_id);
console.log(`[成功] 账号 ${account_id} 已成功下车`);
}
} catch (e) {}
}
// 4. 智能重试机制:处理 Workspace Token 限制
if (!isSuccess) {
const isWorkspaceError = responseText.includes('Must use workspace account for this operation');
if (isWorkspaceError) {
console.log(`[检测到工作区限制] 账号 ${account_id} 需要切换空间 Token,正在换取...`);
try {
// 换取该空间的专有 token
const wsSessionRes = await fetch(
`https://chatgpt.com/api/auth/session?exchange_workspace_token=true&workspace_id=${account_id}&reason=setCurrentAccount`
);
if (wsSessionRes.ok) {
const wsSession = await wsSessionRes.json();
const wsAccessToken = wsSession?.accessToken;
if (wsAccessToken) {
console.log(`[成功] 已获取空间 ${account_id} 的临时 Token,开始重新尝试删除...`);
// 使用空间 token 重试删除请求
const retryResponse = await fetch(
`https://chatgpt.com/backend-api/accounts/${account_id}/users/${user_id}`,
{
method: 'DELETE',
headers: {
Authorization: `Bearer ${wsAccessToken}`,
'Content-Type': 'application/json',
},
}
);
let retryText = '';
try { retryText = await retryResponse.text(); } catch (e) {}
if (retryResponse.status === 200) {
try {
const retryData = JSON.parse(retryText);
if (retryData?.success) {
isSuccess = true;
results.success.push(account_id);
console.log(`[成功] 切换临时 Token 后,账号 ${account_id} 下车成功`);
}
} catch (e) {}
}
if (!isSuccess) {
results.failed.push({ account_id, status: retryResponse.status, reason: '切换 Token 后重试失败', detail: retryText });
console.log(`[失败] 切换临时 Token 重试后依然失败,状态码: ${retryResponse.status}`);
}
} else {
results.failed.push({ account_id, reason: '空间 session 返回数据中未包含 accessToken' });
console.log(`[失败] 无法从空间 ${account_id} 的 session 响应中提取到 Token`);
}
} else {
results.failed.push({ account_id, status: wsSessionRes.status, reason: '请求空间 Token 接口失败' });
console.log(`[失败] 请求空间临时 Token 失败,状态码: ${wsSessionRes.status}`);
}
} catch (wsErr) {
results.failed.push({ account_id, reason: '获取空间 Token 过程中发生错误', error: wsErr.message });
console.log(`[错误] 获取账号 ${account_id} 空间 Token 时发生异常: ${wsErr.message}`);
}
} else {
// 非工作区错误,直接记录并跳过
results.failed.push({ account_id, status: response.status, detail: responseText });
console.log(`[跳过] 账号 ${account_id} 失败(非工作区错误),状态码: ${response.status}`);
}
}
} catch (err) {
results.failed.push({ account_id, error: err.message || String(err) });
console.log(`[错误] 处理账号 ${account_id} 时发生异常,已跳过并继续: ${err.message || err}`);
}
}
// 5. 输出汇总结果
console.log('\n========= 处理结果汇总 =========');
console.log(`成功下车数: ${results.success.length}`);
if (results.success.length > 0) console.log('成功账号 ID 列表:', results.success);
console.log(`失败/跳过数: ${results.failed.length}`);
if (results.failed.length > 0) console.log('失败详情列表:', results.failed);
console.log('=================================');
} catch (globalErr) {
console.error('脚本初始化阶段发生未捕获的错误:', globalErr);
}
})();
💡 技术细节解读:为什么需要“换 Token”?
你可能在代码里注意到了一个很关键的处理逻辑:Workspace Exchange Token。
当你用个人账号的主 Token 去请求删除某些企业空间时,官方 API 会报错:“Must use workspace account for this operation”(必须使用工作区账号进行此操作)。这是因为部分安全策略要求“谁的人谁来踢”。
这个脚本的高明之处就在于它不仅会报错,还能自动解决。当检测到这个特定错误时,它会利用 exchange_workspace_token 参数,向服务端申请一个该空间的临时管理员 Token,拿到新 Token 后再立马发一次 DELETE 请求。这种“曲线救国”的方法大大提高了脚本的成功率。
❓ 常见问题与限制
Q: 退出后能不能重新加回来以此“重置”额度?
A: 不太行。根据技术大牛的推测,Codex 后端的计费逻辑绑定的是 workspace_id + user_id。即便你退出了再重新加入,因为你的 user_id 没变,系统依然记得你在该空间的消耗记录,想通过此法薅羊毛大概率是行不通的。
Q: 那些早就过期或者被封禁(402/停用)的空间能退吗? A: 很遗憾,不能。如果你的空间因为违规被官方风控封禁,或者已经被彻底停用,API 接口会拒绝执行操作。这类空间只能挂在列表里当摆设了,不过好消息是它们通常也不会计费或影响主号正常使用。
Q: 脚本会把我的个人主账号也删了吗? A: 不会。脚本是针对“关联/加入的空间”进行操作,个人主账户是你的根 ID,无法对自己执行退出操作。但为了稳妥起见,操作前记得备份数据,虽然目前看这个脚本非常安全。
总结
这大概是目前清理 ChatGPT 账号环境最高效的方法了。如果你也深受那些乱七八糟的教育空间骚扰,不妨赶紧试试这个脚本,一键清爽,从此告别“账号精神污染”。

评论已关闭