Codex 重置卡查看工具:检查 ChatGPT 邀请奖励与可用次数
#Chatgpt
检查 ChatGPT Codex 邀请活动是否仍有重置卡奖励,查看 rate_limit_reset_credits 可用次数和过期时间,避免继续尝试已失效的邀请流程。
The briefing
快速结论
- 当前 Codex 邀请活动主体已经结束,有入口不代表还能拿到重置卡。
- 这个网页工具适合检查账户里的 rate_limit_reset_credits、可用数量和过期时间。
- 如果你搜索“Codex 重置卡”或“ChatGPT invite rewards”,先确认奖励接口仍返回可用次数,再决定是否继续操作。
- 后续如果 OpenAI 恢复邀请奖励,这里会继续更新可用入口和注意事项。
#0. Chrome插件可以使用~ codex-referral-extension.zip
效果如下:

如果不想用插件,可以按下面的方法。
1. 在网页登录Chatgpt
2. 使用F12 控制台输入以下命令
(async () => {
const PANEL_ID = "codex-referral-panel";
const REFERRAL_KEY = "codex_referral_persistent_invite";
const API_BASE = "/backend-api";
document.getElementById(PANEL_ID)?.remove();
if (location.hostname !== "chatgpt.com") {
throw new Error("请先打开 https://chatgpt.com,再在该页面的 F12 Console 中运行。");
}
const panel = document.createElement("section");
panel.id = PANEL_ID;
panel.innerHTML = `
<style>
#${PANEL_ID} {
position: fixed;
z-index: 2147483647;
right: 20px;
bottom: 20px;
width: min(820px, calc(100vw - 32px));
max-height: calc(100vh - 40px);
color: #171717;
background: #fff;
border: 1px solid #d4d4d4;
border-radius: 8px;
box-shadow: 0 16px 48px rgba(0, 0, 0, .22);
font: 14px/1.5 ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
"Segoe UI", sans-serif;
overflow: hidden;
}
#${PANEL_ID} * { box-sizing: border-box; }
#${PANEL_ID} header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 16px;
color: #fff;
background: #171717;
}
#${PANEL_ID} h2 {
margin: 0;
font-size: 15px;
font-weight: 650;
letter-spacing: 0;
}
#${PANEL_ID} .close {
width: 28px;
height: 28px;
padding: 0;
color: #fff;
background: transparent;
border: 0;
font-size: 20px;
cursor: pointer;
}
#${PANEL_ID} .body {
max-height: calc(100vh - 96px);
padding: 16px;
overflow: auto;
}
#${PANEL_ID} .summary {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
margin-bottom: 14px;
}
#${PANEL_ID} .metric {
padding: 9px 10px;
background: #f5f5f5;
border: 1px solid #e5e5e5;
border-radius: 6px;
}
#${PANEL_ID} .metric span {
display: block;
color: #737373;
font-size: 12px;
}
#${PANEL_ID} .metric strong {
display: block;
margin-top: 2px;
font-size: 14px;
overflow-wrap: anywhere;
}
#${PANEL_ID} .section-title {
margin: 14px 0 8px;
font-size: 13px;
font-weight: 700;
}
#${PANEL_ID} .table-wrap {
max-height: 210px;
margin-bottom: 14px;
overflow: auto;
border: 1px solid #e5e5e5;
border-radius: 6px;
}
#${PANEL_ID} table {
width: 100%;
min-width: 680px;
border-collapse: collapse;
background: #fff;
}
#${PANEL_ID} th,
#${PANEL_ID} td {
padding: 8px 9px;
border-bottom: 1px solid #f0f0f0;
text-align: left;
vertical-align: top;
font-size: 12px;
}
#${PANEL_ID} th {
position: sticky;
top: 0;
z-index: 1;
color: #525252;
background: #fafafa;
font-weight: 700;
}
#${PANEL_ID} td {
color: #262626;
overflow-wrap: anywhere;
}
#${PANEL_ID} a {
color: #2563eb;
text-decoration: none;
}
#${PANEL_ID} a:hover { text-decoration: underline; }
#${PANEL_ID} .empty {
color: #737373;
text-align: center;
}
#${PANEL_ID} label {
display: block;
margin-bottom: 6px;
font-weight: 600;
}
#${PANEL_ID} input {
width: 100%;
height: 40px;
padding: 0 11px;
color: #171717;
background: #fff;
border: 1px solid #a3a3a3;
border-radius: 6px;
outline: none;
}
#${PANEL_ID} input:focus {
border-color: #171717;
box-shadow: 0 0 0 2px rgba(23, 23, 23, .12);
}
#${PANEL_ID} .actions {
display: flex;
gap: 8px;
margin-top: 10px;
}
#${PANEL_ID} button.action {
height: 38px;
padding: 0 13px;
border: 1px solid #a3a3a3;
border-radius: 6px;
background: #fff;
cursor: pointer;
font-weight: 600;
}
#${PANEL_ID} button.primary {
flex: 1;
color: #fff;
background: #171717;
border-color: #171717;
}
#${PANEL_ID} button:disabled {
cursor: not-allowed;
opacity: .5;
}
#${PANEL_ID} .status {
min-height: 72px;
max-height: 220px;
margin: 14px 0 0;
padding: 12px;
overflow: auto;
overflow-wrap: anywhere;
color: #262626;
background: #fafafa;
border: 1px solid #e5e5e5;
border-left: 4px solid #a3a3a3;
border-radius: 6px;
}
#${PANEL_ID} .status.ok {
color: #14532d;
background: #f0fdf4;
border-color: #bbf7d0;
border-left-color: #16a34a;
}
#${PANEL_ID} .status.error {
color: #7f1d1d;
background: #fef2f2;
border-color: #fecaca;
border-left-color: #dc2626;
}
#${PANEL_ID} .status.warn {
color: #713f12;
background: #fffbeb;
border-color: #fde68a;
border-left-color: #f59e0b;
}
#${PANEL_ID} .status-title {
margin: 0 0 6px;
font-size: 14px;
font-weight: 750;
}
#${PANEL_ID} .status-line {
margin-top: 3px;
font-size: 13px;
line-height: 1.45;
}
</style>
<header>
<h2>Codex 邀请检查与发送</h2>
<button class="close" title="关闭" aria-label="关闭">×</button>
</header>
<div class="body">
<div class="summary">
<div class="metric"><span>网页当前套餐</span><strong data-field="plan">读取中</strong></div>
<div class="metric"><span>可邀请次数</span><strong data-field="quota">读取中</strong></div>
<div class="metric"><span>重置卡</span><strong data-field="credits">读取中</strong></div>
<div class="metric"><span>账号 ID</span><strong data-field="account">读取中</strong></div>
</div>
<div class="section-title">已发送邀请明细</div>
<div class="table-wrap">
<table>
<thead>
<tr>
<th>邮箱</th>
<th>状态</th>
<th>过期时间</th>
<th>奖励</th>
<th>邀请链接</th>
</tr>
</thead>
<tbody data-field="referrals">
<tr><td class="empty" colspan="5">读取中</td></tr>
</tbody>
</table>
</div>
<div class="section-title">我获得的重置卡奖励</div>
<div class="table-wrap">
<table>
<thead>
<tr>
<th>来源</th>
<th>状态</th>
<th>领取时间</th>
<th>过期时间</th>
<th>使用时间</th>
</tr>
</thead>
<tbody data-field="reward-credits">
<tr><td class="empty" colspan="5">读取中</td></tr>
</tbody>
</table>
</div>
<label for="codex-referral-email">受邀邮箱</label>
<input id="codex-referral-email" type="email" autocomplete="off"
placeholder="[email protected]">
<div class="actions">
<button class="action" data-action="refresh">刷新状态</button>
<button class="action primary" data-action="send" disabled>发送邀请</button>
</div>
<div class="status">正在读取当前网页会话…</div>
</div>
`;
document.body.appendChild(panel);
const $ = (selector) => panel.querySelector(selector);
const planEl = $('[data-field="plan"]');
const quotaEl = $('[data-field="quota"]');
const creditsEl = $('[data-field="credits"]');
const accountEl = $('[data-field="account"]');
const referralsEl = $('[data-field="referrals"]');
const rewardCreditsEl = $('[data-field="reward-credits"]');
const emailEl = $("#codex-referral-email");
const refreshButton = $('[data-action="refresh"]');
const sendButton = $('[data-action="send"]');
const statusEl = $(".status");
let token = "";
let accountId = "";
let busy = false;
let inviteQuotaRemaining = 0;
const setStatus = (message, type = "") => {
statusEl.className = `status ${type}`.trim();
statusEl.replaceChildren();
const lines = Array.isArray(message) ? message : String(message ?? "").split("\n");
const title = lines.shift() || "";
const titleEl = document.createElement("div");
titleEl.className = "status-title";
titleEl.textContent = title;
statusEl.appendChild(titleEl);
for (const line of lines.filter(Boolean)) {
const lineEl = document.createElement("div");
lineEl.className = "status-line";
lineEl.textContent = line;
statusEl.appendChild(lineEl);
}
};
const setBusy = (value) => {
busy = value;
refreshButton.disabled = value;
emailEl.disabled = value;
sendButton.disabled = value || !token || !accountId;
};
const formatTime = (iso) => {
if (!iso) return "";
return new Intl.DateTimeFormat("zh-CN", {
timeZone: "Asia/Shanghai",
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: false,
})
.format(new Date(iso))
.replace(/\//g, "-");
};
const grantText = (grants) => {
if (!Array.isArray(grants) || grants.length === 0) return "";
return grants
.map((grant) => {
const who = grant.recipient === "referrer" ? "邀请人" : "被邀请人";
const type =
grant.grant_type === "rate_limit_reset_credit" ? "重置卡" : grant.grant_type;
return `${who} +${grant.amount ?? 1} ${type}`;
})
.join(";");
};
const creditSourceText = (credit) => {
const title = credit?.title || "";
const description = credit?.description || "";
const profile = credit?.profile_user_id || "";
const text = `${title} ${description} ${profile}`.toLowerCase();
if (/codex team|thanks for using codex|official|官方/.test(text)) {
return "官方免费赠送";
}
return description || title || profile || credit?.reset_type || "未知来源";
};
const creditUseTime = (credit) => {
if (credit?.redeemed_at) return formatTime(credit.redeemed_at);
if (credit?.redeem_started_at) return `兑换中:${formatTime(credit.redeem_started_at)}`;
return "";
};
const appendCell = (row, text, className = "") => {
const cell = document.createElement("td");
cell.textContent = text ?? "";
if (className) cell.className = className;
row.appendChild(cell);
return cell;
};
const renderTableMessage = (tbody, colspan, message, className = "empty") => {
tbody.replaceChildren();
const row = document.createElement("tr");
appendCell(row, message, className).colSpan = colspan;
tbody.appendChild(row);
};
const renderReferrals = (items) => {
referralsEl.replaceChildren();
if (!Array.isArray(items) || items.length === 0) {
renderTableMessage(referralsEl, 5, "还没有已发送邀请记录");
return;
}
for (const item of items) {
const row = document.createElement("tr");
appendCell(row, item.email || "");
appendCell(row, item.status || "");
appendCell(row, formatTime(item.expires_at));
appendCell(row, grantText(item.grants));
const linkCell = document.createElement("td");
if (item.referral_link) {
const link = document.createElement("a");
link.href = item.referral_link;
link.target = "_blank";
link.rel = "noreferrer";
link.textContent = "打开";
linkCell.appendChild(link);
} else {
linkCell.textContent = "";
}
row.appendChild(linkCell);
referralsEl.appendChild(row);
}
};
const renderRewardCredits = (credits) => {
rewardCreditsEl.replaceChildren();
if (!Array.isArray(credits) || credits.length === 0) {
renderTableMessage(rewardCreditsEl, 5, "还没有重置卡奖励记录");
return;
}
for (const credit of credits) {
const row = document.createElement("tr");
appendCell(row, creditSourceText(credit));
appendCell(row, credit.status || "");
appendCell(row, formatTime(credit.granted_at));
appendCell(row, formatTime(credit.expires_at));
appendCell(row, creditUseTime(credit));
rewardCreditsEl.appendChild(row);
}
};
const parseResponse = async (response) => {
const contentType = response.headers.get("content-type") || "";
const text = await response.text();
if (contentType.includes("application/json")) {
try {
return text ? JSON.parse(text) : null;
} catch {
return { detail: "服务器返回了无法解析的 JSON", raw: text.slice(0, 500) };
}
}
return {
detail: text
? `服务器返回非 JSON 内容:${text.slice(0, 300)}`
: "服务器没有返回内容",
};
};
const readableValue = (value) => {
if (value === null || value === undefined || value === "") return "";
if (typeof value === "string") return value;
if (typeof value === "number" || typeof value === "boolean") return String(value);
if (Array.isArray(value)) return value.map(readableValue).filter(Boolean).join(", ");
const lines = [];
if (value.message) lines.push(String(value.message));
if (value.failed_emails?.length) {
lines.push(`失败邮箱:${value.failed_emails.join(", ")}`);
}
if (value.code) lines.push(`错误代码:${value.code}`);
if (value.error) {
const errorText = readableValue(value.error);
if (errorText) lines.push(`错误:${errorText}`);
}
if (value.ineligible_reason) {
const reasonText = readableValue(value.ineligible_reason);
if (reasonText) lines.push(`不符合原因:${reasonText}`);
}
if (value.ineligible_reason_code) {
lines.push(`不符合原因代码:${value.ineligible_reason_code}`);
}
if (value.detail && value.detail !== value) {
const detailText = readableValue(value.detail);
if (detailText) lines.push(detailText);
}
const unique = [...new Set(lines.filter(Boolean))];
return unique.length ? unique.join("\n") : JSON.stringify(value, null, 2);
};
const responseDetail = (data, fallback = "") =>
readableValue(data?.detail) ||
readableValue(data?.message) ||
(typeof data === "string" ? data : "") ||
fallback;
const responsePayload = (data) =>
data?.detail && typeof data.detail === "object" ? data.detail : data || {};
const responseMessage = (data, fallback = "") => {
const payload = responsePayload(data);
return payload.message || data?.message || responseDetail(data, fallback);
};
const failedEmails = (data) => {
const payload = responsePayload(data);
return Array.isArray(payload.failed_emails) ? payload.failed_emails : [];
};
const inviteResultTitle = (ok, message) => {
if (ok) return "邀请发送成功";
if (/cannot be referred/i.test(message)) return "该邮箱暂时不能被邀请";
return "邀请没有发送成功";
};
const api = async (path, options = {}, useAccount = true) => {
const response = await fetch(`${API_BASE}${path}`, {
...options,
credentials: "include",
headers: {
accept: "application/json",
authorization: `Bearer ${token}`,
...(useAccount && accountId ? { "chatgpt-account-id": accountId } : {}),
...(options.body ? { "content-type": "application/json" } : {}),
...(options.headers || {}),
},
});
return {
ok: response.ok,
status: response.status,
data: await parseResponse(response),
};
};
const getSession = async () => {
const response = await fetch("/api/auth/session", {
credentials: "include",
headers: { accept: "application/json" },
});
const session = await parseResponse(response);
token = session?.accessToken || session?.access_token || "";
if (!response.ok || !token) {
throw new Error("网页会话中没有 Access Token。请确认当前 chatgpt.com 页面已登录,然后刷新页面重试。");
}
};
const selectAccount = async () => {
const result = await api("/wham/accounts/check", {}, false);
if (!result.ok) {
throw new Error(`读取账号失败:${responseDetail(result.data, "请刷新页面后重试")}`.trim());
}
accountId =
result.data?.default_account_id ||
result.data?.account_ordering?.[0] ||
result.data?.accounts?.[0]?.id ||
"";
if (!accountId) {
throw new Error("服务器没有返回可用的 ChatGPT 账号 ID。");
}
};
const refresh = async (message = "正在刷新当前网页账号状态…") => {
setBusy(true);
setStatus(message);
try {
await getSession();
await selectAccount();
const [usage, rules, referrals, resetCredits, frontendEligibility] = await Promise.all([
api("/wham/usage"),
api(`/wham/referrals/eligibility_rules?referral_key=${encodeURIComponent(REFERRAL_KEY)}`),
api(`/wham/referrals?referral_key=${encodeURIComponent(REFERRAL_KEY)}`),
api("/wham/rate-limit-reset-credits"),
api(`/referrals/invite/eligibility?referral_key=${encodeURIComponent(REFERRAL_KEY)}`),
]);
const failures = [];
if (usage.ok) {
planEl.textContent = usage.data?.plan_type || "未知";
} else {
planEl.textContent = "读取失败";
failures.push(`套餐:${responseDetail(usage.data, "请稍后重试")}`);
}
const frame = rules.ok ? rules.data?.time_frame_rules?.[0] || {} : {};
const sent = Number(frame.invites_sent);
const total = Number(frame.invites_total);
const remaining =
Number.isFinite(sent) && Number.isFinite(total) ? Math.max(0, total - sent) : null;
if (rules.ok) {
inviteQuotaRemaining = remaining === null ? 0 : remaining;
quotaEl.textContent =
remaining === null ? "0 次" : `${remaining} 次(已用 ${sent}/${total})`;
} else {
inviteQuotaRemaining = 0;
quotaEl.textContent = "0 次";
failures.push("可邀请次数:额度接口不可用,按 0 处理");
}
if (resetCredits.ok) {
const availableCredits =
resetCredits.data?.available_count ??
usage.data?.rate_limit_reset_credits?.available_count ??
"未知";
const totalEarnedCredits = resetCredits.data?.total_earned_count;
creditsEl.textContent =
totalEarnedCredits === undefined
? `${availableCredits}`
: `可用 ${availableCredits},奖励 ${totalEarnedCredits}`;
renderRewardCredits(resetCredits.data?.credits || []);
} else {
const fallbackCredits = usage.ok
? usage.data?.rate_limit_reset_credits?.available_count
: undefined;
creditsEl.textContent =
fallbackCredits === undefined ? "读取失败" : `可用 ${fallbackCredits}`;
renderTableMessage(
rewardCreditsEl,
5,
`重置卡奖励读取失败:${responseDetail(resetCredits.data, "请稍后重试")}`,
);
failures.push(`重置卡奖励:${responseDetail(resetCredits.data, "请稍后重试")}`);
}
accountEl.textContent = accountId;
if (referrals.ok) {
renderReferrals(referrals.data?.items || []);
} else {
renderTableMessage(
referralsEl,
5,
`邀请明细读取失败:${responseDetail(referrals.data, "请稍后重试")}`,
);
failures.push(`邀请明细:${responseDetail(referrals.data, "请稍后重试")}`);
}
console.log("Codex 邀请状态:", {
plan_type: usage.ok ? usage.data?.plan_type : null,
reset_cards_available: resetCredits.ok
? resetCredits.data?.available_count
: usage.data?.rate_limit_reset_credits?.available_count,
reset_cards_total_earned: resetCredits.ok ? resetCredits.data?.total_earned_count : null,
invites_sent: frame.invites_sent,
invites_total: frame.invites_total,
invite_remaining: remaining,
effective_invite_remaining: inviteQuotaRemaining,
time_frame: frame.time_frame,
account_id: accountId,
partial_failures: failures,
});
if (referrals.ok) {
console.table(
(referrals.data?.items || []).map((item, index) => ({
index: index + 1,
email: item.email,
status: item.status,
expires_at: formatTime(item.expires_at),
referral_id: item.referral_id,
grants: grantText(item.grants),
referral_link: item.referral_link,
})),
);
}
if (resetCredits.ok) {
console.table(
(resetCredits.data?.credits || []).map((credit, index) => ({
index: index + 1,
source: creditSourceText(credit),
status: credit.status,
granted_at: formatTime(credit.granted_at),
expires_at: formatTime(credit.expires_at),
used_at: creditUseTime(credit),
profile_user_id: credit.profile_user_id,
credit_id: credit.id,
})),
);
}
const eligibilityLine =
frontendEligibility.ok && frontendEligibility.data?.should_show !== false
? "网页入口:当前可显示"
: "网页入口:当前未显示,面板仍可按接口结果操作";
const successCount = [usage, rules, referrals, resetCredits].filter((r) => r.ok).length;
const statusTitle =
failures.length === 0
? "状态读取完成。"
: successCount > 0
? "状态已部分读取。"
: "状态读取失败。";
const referralCountText = referrals.ok
? `${referrals.data?.items?.length ?? 0} 条`
: "不可用";
const rewardCountText = resetCredits.ok
? `${resetCredits.data?.credits?.length ?? 0} 条`
: "不可用";
setStatus(
[
statusTitle,
`套餐:${planEl.textContent}`,
`可邀请:${quotaEl.textContent}`,
`重置卡:${creditsEl.textContent}`,
`邀请明细:${referralCountText}`,
`奖励明细:${rewardCountText}`,
eligibilityLine,
...failures.map((failure) => `未读取:${failure}`),
].join("\n"),
failures.length === 0 ? "ok" : successCount > 0 ? "warn" : "error",
);
} catch (error) {
token = "";
accountId = "";
inviteQuotaRemaining = 0;
planEl.textContent = "读取失败";
quotaEl.textContent = "读取失败";
creditsEl.textContent = "读取失败";
accountEl.textContent = "读取失败";
renderReferrals([]);
renderRewardCredits([]);
setStatus(error instanceof Error ? error.message : String(error), "error");
} finally {
setBusy(false);
}
};
const sendInvite = async () => {
if (busy) return;
const email = emailEl.value.trim();
if (!emailEl.checkValidity() || !email) {
emailEl.reportValidity();
return;
}
const confirmed = window.confirm(
`确认使用当前网页账号发送 1 次 Codex 邀请?\n\n收件邮箱:${email}\n账号 ID:${accountId}`,
);
if (!confirmed) return;
setBusy(true);
setStatus(`正在向 ${email} 发送邀请…`);
try {
// 发送前重新读取网页会话,避免使用已经过期的 Token。
await getSession();
await selectAccount();
const result = await api("/wham/referrals/invite", {
method: "POST",
body: JSON.stringify({
referral_key: REFERRAL_KEY,
emails: [email],
}),
});
const invite =
result.data?.invites?.[0] ||
result.data?.items?.[0] ||
result.data?.referral ||
result.data ||
{};
const detail = responseMessage(
result.data,
result.ok ? "服务器已接受邀请请求" : "服务器拒绝了邀请请求",
);
const failed = failedEmails(result.data);
const resultTitle = inviteResultTitle(result.ok, detail);
const resultLines = result.ok
? [
invite.email ? `邮箱:${invite.email}` : "",
invite.referral_id ? `Referral ID:${invite.referral_id}` : "",
invite.invite_url || invite.referral_link
? `邀请链接:${invite.invite_url || invite.referral_link}`
: "",
"已自动刷新邀请额度和明细。",
]
: [
failed.length ? `邮箱:${failed.join(", ")}` : `邮箱:${email}`,
`结果:${detail}`,
"邀请没有发出,当前邮箱不会出现在已发送邀请列表。",
];
const statusMessage = [resultTitle, ...resultLines.filter(Boolean)].join("\n");
setStatus(statusMessage, result.ok ? "ok" : "error");
console.log("Codex 邀请响应:", {
http_status: result.status,
ok: result.ok,
response: result.data,
});
if (result.ok) {
await refresh("发送成功,正在重新读取邀请额度…");
setStatus(statusMessage, "ok");
}
} catch (error) {
setStatus(error instanceof Error ? error.message : String(error), "error");
} finally {
setBusy(false);
}
};
$(".close").addEventListener("click", () => panel.remove());
refreshButton.addEventListener("click", () => refresh());
sendButton.addEventListener("click", sendInvite);
await refresh();
})();
效果如下:

Is this still live?
Community signal
39 reports
