[DEAD] 0 or 1美金5人头的ChatGPT Team
0或1美金ChatGPT Team优惠已彻底死亡,大量封号。
1. 关键信息
- 通过新账号+无痕模式+域名邮箱可0美元试用ChatGPT Team(5 seats),试用期一个月(#1 #3 #52),现已失效。
- 取消订阅后,部分用户仍可使用到月底(#8),但近期风控升级后取消即失效(#111 #254)。
- 可使用CLIProxyAPI将OAuth登录包装为API,实现多账号轮询,突破额度限制(#176 #195)。
- 风控加强:同一张卡开多个账号受限(#131),Privacy虚拟卡近期被拒(#221 #292),Citi虚拟卡可用但需注意地址(#141)。
- 新回复确认优惠已死:任何新注册均无法获得0或1美元试用(#306),促销链接无效(#305)。
- 大量封号持续:刚开的新号(#307)、域名邮箱账号(#308)、上周开的Team(#310)、未取消的Team(#312)、上个月试用完的号(#313)均被deactivate;仅少数同时薅Plus和Team的域名邮箱仍健在(#311)。
- Privacy虚拟卡无法使用后,有用户询问替代方案,但无Citi卡(#315)。
2. 羊毛/优惠信息
- ChatGPT Team 0美元试用:新账号+域名邮箱(如Cloudflare转发)可0元开通5人团队版(#1 #52 #234),现已失效。
- 1美元试用:部分用户可通过专属链接以1美元开通(#1),现已失效。
- CLIProxyAPI:免费开源工具,将OAuth登录转为API,支持多账号轮询(#176),可部署到本地(#304)。
- 域名邮箱:Cloudflare免费托管域名,catch-all转发(#234)。
- 虚拟卡:Privacy、Citi虚拟卡用于付款,但Privacy近期被拒(#292),Citi可设spending limit(#206);Privacy不能用了,用户询问替代方案(#315)。
- 其他:Gemini送一年会员(#14);Amex Biz Plat报销可覆盖ChatGPT Team费用(#285 #299)。
- 促销链接:https://chatgpt.com/?promoCode=STRIPEPERKSGPT4BIZ 试多种邮箱均无效,仅个人Plus试用(#305)。
- Claude Pro折扣码:有用户询问折扣码(#316),但无有效信息(#317)。
3. 最新动态
- 优惠已彻底死亡:多数用户反馈无法再获得0美元或1美元试用(#230 #283 #285 #297 #306),仅极少数新设备+新域名邮箱可能成功(#237),但新回复确认已DEAD(#306)。
- 封号潮升级:大量Team账号被封(#146 #148 #151),尤其是使用VPN或可疑卡头的用户(#147)。新增多起封号案例:还没用的新号(#307)、域名邮箱账号(#308)、上周开的Team(#310)、未取消的Team(#312)、上个月试用完的号(#313)均被deactivate。有用户同时薅Plus和Team的域名邮箱仍健在(#311),但整体封杀严重。
- 风控判断推测:新账号直接试用可能触发风控(#314);IP影响已不明显(#314)。
- 取消订阅后立即失效:近期取消即失效(#111 #254),与早期可用到月底矛盾。
- 替代方案:有分销网站提供4年半价Team席位($25/月/2 seats)(#299);Plus用户可正常使用(#304)。
- Privacy虚拟卡失效后:用户询问无Citi卡时的替代方案(#315),暂无新方案。
4. 争议或不同意见
- 取消后是否可用:早期取消后可用到月底(#8),近期取消即失效(#111 #254),存在矛盾DP。
- 额度是否减半:部分用户发现Business版额度降至Plus的一半(#170 #190),但官方文档显示一致(#194)。
- CLIProxyAPI轮询策略:round-robin vs fill-first,有用户认为fill-first更省token(#195),也有用户建议session-affinity(#275)。
- 本地部署CLIProxyAPI:有用户认为部署到本地可能降低封号风险(#304),但无明确证据。
- 封号原因:新号直接试用(#314)vs IP问题(#147),存在不同看法。
- Claude Pro折扣码:有用户询问(#316),但无有效信息(#317)。
5. 行动建议
- 立即停止尝试:该优惠已彻底死亡,新注册大概率失败或很快被封(#306 #307 #308 #310 #312)。
- 已上车用户:尽快取消订阅,避免被反薅(#127);使用虚拟卡或锁卡,防止续费(#121);注意即使未取消也可能被封(#312)。
- 替代方案:考虑Amex Biz Plat报销或分销网站半价Team(#299);或直接订阅ChatGPT Plus/Pro(#304)。
- 注意安全:避免使用可疑VPN或卡头,防止封号(#147);新账号请先正常使用一段时间再尝试试用(#314推测)。
- 虚拟卡替代:Privacy失效后,若无Citi卡,可尝试其他虚拟卡服务或实体卡(#315),但需注意风控。
Update: 新用户有机会0元开通,没有的直接开个新账号
Update2: 更新新用户0元开通的流程以及截图
Update3: 更新开通链接
【引用自 meika3】:
更新:找到了链接
ChatGPT
old
1美金开通
https://openai.com/chatgpt/team/
image918×404 29.5 KB
image1920×2111 268 KB
image1683×958 30.3 KB
image1668×959 59.3 KB
ChatGPT for business, powered by OpenAI’s most advanced models
ChatGPT Team is the fastest way to start using ChatGPT for work—with a shared workspace, admin controls, and connectors to your company tools.
Try for $1See pricing
免费开通
无痕模式创建新账号 登录后你能看到上面显示有免费开通
image2300×534 9.59 KB
开通5人的Business
image1089×1059 50.6 KB
薅完记得取消订阅
https://chatgpt.com/admin/billing?tab=plan
别被反薅了
image1683×958 45.5 KB
image1683×958 39.4 KB
这个只有一个月吧?
一个月一个新账号啊
感谢分享 这下我也能愉快地画图了。
不知道可以维持多久
提前取消会维持到月底吗?
我现在试试
image1683×958 45.5 KB
会维持到月底
https://chatgpt.com/admin/billing?tab=plan
牛逼deal
这deal 让我无所适从
666
用了c1的一次性信用卡,但还是留名。月底大家提醒我一下
现在就可以取消
gemini送一年的会员。还不够你做图?
让我想起了隔壁365个邮箱的麦当劳
细说365邮箱麦当劳怎么玩
每天都过生日啊
【引用自 打豆豆】:
这下我也能愉快地画图了。
我要把豆老師舉報成金卡會員。
@打豆豆 豆老師是不是編輯帖子了…我為什麼明明一開始看見的是什麼地圖…
聊天差别不大,但作图的话
【引用自 aqua】:
泥潭征友活动
Gemini 简直是人工智障
欧洲IP+PayPal可以解决续费问题
Sorry, you’re not eligible for this promotional discount.
开过的就开新帐号
curl -s -o /dev/null -w "%{redirect_url}\n" https://lancdn.co/ctpo
https://chatgpt.com/?promo_campaign=team1dollar&utm_campaign=WEB-team_try_for_1&utm_internal_medium=referral&utm_internal_source=openai_team#team-pricing
utm_internal_medium=referral
偷偷发refer链接是吧
每个月换账号GPT会降智吧,亲测新账号原版GPT因为没有我的用户记忆,跟我自己账号的GPT输出差别很大。
【引用自 Michael123456】:
没有我的用户记忆
不一定是坏事
需要建个新号么,用常用的个人号付款不成功,用Link还是手动输入信用卡都不行
有可能 毕竟这个是拉新的活动
画图是指什么?文生图吗
你知道记忆的本质是更长的上下文吗?这都是有代价的
promote 结束了?
现在直接开有机会0元 不行就换个账号
要先sign up 嘛?
要的zs
有没有人一元车可以上
【引用自 uhhhh】:
https://openai.com/chatgpt/team/
teams 用 5 pro 限制会比直接开 pro 大吗
yes zs
好像死了?
没了zszs
刚蹭了朋友的车,请问team相比个人有啥劣势吗?
你朋友是1刀上的车?
有可能,说让我用一个月体验体验
team没有烈士,你用完了额度把号踢出team再拉个新号又有额度了,个人应该做不到
能不能问问,那说明1刀deal还存在,只是target了?
不是,他们几个人一起开的号,多了个名额让我先用(估计让我以后一起分摊)
image1028×283 3.34 KB
stealth account, no upgrade for free option
更新:找到了链接
ChatGPT
没dead 换了个设备就有试用0元了
这是1刀还是0刀的链接 我更新一下主题
0刀 早上八点
好像可以新号开个新的会员然后拉老号,
刚试了试没问题,0元然后icloud开了五个号
请问一下为什么要开5个
这个有个人pro的agent模式吗?
因为五个免费不用白不用,一晚上干掉了26%的周limit,差不多2-3个号换着用可以就token自由了
可以登陆到OpenCode用agent
是用codex么,同一份代码换不同的账号?
是,可以切账号也可以用路由把几个账号聚合
什么是路由器聚合, 这个么
【引用自 未知】:
用Antigravity白嫖claude API 购物折扣
还有个办法 opencode 这个插件 GitHub - NoeFabris/opencode-antigravity-auth: Enable Opencode to authenticate against Antigravity (Google's IDE) via OAuth so you can use Antigravity rate limits and access models …
CLIProxyAPI
github.com
GitHub - router-for-me/CLIProxyAPI: Wrap Gemini CLI, Antigravity, ChatGPT Codex,...
Wrap Gemini CLI, Antigravity, ChatGPT Codex, Claude Code, Qwen Code, iFlow as an OpenAI/Gemini/Claude/Codex compatible API service, allowing you to enjoy the free Gemini 2.5 Pro, GPT 5, Claude, Qwen model through API
谢谢大佬 学习一下
谢谢大佬! 每个人都需要注册5个新账号吗?
刚刚注册了一个trial team,拿了一个apikey,但是一用apikey就说insufficient_quota,是需要别的设置吗?
api另外收费 apikey是通过反代搞出来的
没有"需要"这种事 只是蹬满最好的
【引用自 uhhhh】:
反代
怎么这么弄? 谢谢
看我其他帖子
学习了一下,应该是那个sub2api吧? 用这个sub2api搞的api能给openclaw之类的用吗? sub2api界面上只看到给Codex CLI和OpenCode
看antigravity的帖子 我用那里面的工具
我自建的 codelib.re 域名邮箱被说
Email is invalid
另一个 eu.org 的倒是可以,但是那个是托管在阿里云企业邮箱的,没有 RFC 5233 支持,只能搞个 catch all 邮箱暂时用着。感觉如果要封堵这个缺口看起来也很简单,限制一些常见邮箱域名就结束了?
team plan怎么可能限制常见域名 小公司用的肯定都有自己的域名
不是正因为哪怕是小公司也都有自己的域名,所以常见的 gmail iCloud 什么的可以被禁止吗?
有很多research team都用outlook和gmail没有自己的域名的 限制域名基本是给anthropic送人头的昏招
银行卡咋解决的…好像一张卡能绑定的账号有限
虚拟卡zs
你可以试试,让他把关于你的所有context都summarize出来,你说你要移到别的账号,然后你开新账号的时候把这个导入试试。
大佬, 这个cliproxyapi能支持tool call吗?能text to image吗?
tool call跟中转没关系,不是一个维度的东西,不影响。
text to image我不知道,应该不行
icloud生成虚拟邮箱么
github.com/PastKing/tgbot-verify
oaiteam/invite.py
main
import json
import os
import sys
from typing import List
import requests
ACCOUNT_ID = os.getenv("ACCOUNT_ID", "32bfda....b22")
TOKEN = os.getenv(
"TOKEN",
"eyYmQwZSI.....Y6vBlVVKNmBmY",
)
def prompt_emails() -> List[str]:
raw_value = input("Enter emails to invite (comma or semicolon separated): ").strip()
emails = [
email.strip()
for email in raw_value.replace(";", ",").split(",")
此文件已被截断。 显示原始文件
找到了一个自动化teams注册的脚本
问一下,薅完以后可以立马就取消订阅吗?我点了一下取消订阅,弹出来警告说workspace里的数据和Chat history会立马失效啥的
谢谢!
我取消了,还是一个月到期
可以 没有影响
大佬,创建了5个api key,轮询 用什么tool啊?
CLIProxyAPI
对 我之前搞错了 搞了5个api key 。。
一个就行了 轮询5个chatgptzhang hu
api要额外收费的
不是 我是说cpa的api key。
我之前生成了5个。。 结果一个就可以了 对应5个oauth
cpa会自动轮训。不过我觉得这个策略不好,会让cache hit rate大幅度降低。应该一个账号用完后再继续下一个账号
image569×165 4.16 KB
一个蹬完才会下一个
话说你的main agent 就是选的 openai api key 然后用cpa这个吗?
我的key搞起了 但是一直没有换main agent 导致再次rate limit用不了
但是我不太明白的是 我是oauth正常登录的,也没有用codex的model,pro 理论上来说 应该是unlimited的聊天。
【引用自 Chickenrice】:
我是oauth正常登录的,也没有用codex的model,pro 理论上来说 应该是unlimited的聊天
谁说的,oauth登陆就是codex反代(openai那边看来你在用codex登陆),你就算用chat模型也要走codex的quota
跟openclaw这边agent设置没关系,你绑定cpa的key就行了,cap会自己轮询,出问题你去cpa的dashboard查,大概率你理解错了或者搞错了什么
那cpa也是吗?
那这样看来还是要搞一个免费的模型 平时聊天啊。
cpa就是假装codex 你才有额度用的
what is cpa?
github.com
GitHub - router-for-me/CLIProxyAPI: Wrap Gemini CLI, Antigravity, ChatGPT Codex,...
Wrap Gemini CLI, Antigravity, ChatGPT Codex, Claude Code, Qwen Code, iFlow as an OpenAI/Gemini/Claude/Codex compatible API service, allowing you to enjoy the free Gemini 2.5 Pro, GPT 5, Claude, Qwen model through API
如果在这个cliproxyapi后面加了gemini和chatgpt,它能自动轮换吗?还是需要特殊设置?
明显模型不同啊
我用icloud邮箱提示要工作邮箱 是识别改了吗
你进错了页面
是的,cliproxyapi不能设置这种轮换是吧?那只能在客户端做了
要么想办法映射模型,要么弄个像opencode那样多任务不同模型
你是想做什么?
可能我想多了,一般的聊天或者任务我不care是用chatgpt还是gemini,就是想一个用完了就用另外一个。
那就是映射了
把不同模型都匹配到一个模型里
你想host一个API中转做这事吗
不想host太多 前面我就问cliproxyapi能做这个就好了
有别的
这类的轮子很多的
image2283×374 18.4 KB
理论上是支持这个功能的 但是我设置后测试是无效的 可能我设置错了 你可以研究一下这几个设置项
醍醐灌顶了 好像是我的ip的问题 换了个美国的就对了
现在免费注册的 取消直接就deactivate了
感觉是bug 但是发生了
image712×504 41.2 KB
可能不是BUG 最近chatgpt在杀free trial
我这周初开的 取消了没给我end trial 看看有没有其他DP?
懂了 虽然取消的时候说4月截止:
image650×341 20.3 KB
那最后一天取消吧 反正我用的virtual card已经deactivated了
我试了两个号都是取消了trial就不行了,Sam Altman
我周三晚上开了一条新的,取消还没问题
为啥你们还能开出来 我支付每次都失败
信用卡说没看到任何charge
预付卡吗?
就是普通信用卡啊
那就不知道了
你是网页注册 然后同一个地址 每个月都能注册出来么
对的,我昨天也发生了,想着来这个帖子说一声,转头就忘记了。
前天没问题,应该是风控升级了。
用虚拟卡就行,反正锁卡也不怕忘。不然就自己提前几天取消吧
哪家给虚拟卡啊
我用 Privacy 和 Citi 的 virtual number 反正都不行
Received unknown parameter: payment_method_options[card][network_options]
privacy我可以,你从其他地方找原因,比如地址和邮箱
我privacy开过好几个号了,光昨天就俩
懂了。好像现在不走原来的那个 Stripe checkout 了。退出,回到 ChatGPT 界面,用户名下面有 claim offer 从那边过去 checkout 就对了。
意思是 现在取消就是立刻取消,不给一个月试用team? 所以得29天左右取消?
我一个月之前注册了,过一天就取消了,早上收到邮件说our ChatGPT Business trial has ended,但是刚刚我的信用卡被charge了$18.05,咋整的?
找客服退钱吧
对的,不能取消
我是手机上checkout的。没看到什么变化,还是stripe
yes 用虚拟卡的话地址可以随便填 真信用卡的话可以jig一下地址 保证邮编对就行 一张卡不能开超过2个账号 (不过现在风控变严 可以假设第二个账号也会封)
确定是chatgpt的吗 这个金额不太对啊 一个seat是25/月 免费是5个seat 一次会直接扣你125
你这明显是网页/网络之类的问题 不是信用卡的问题 刷新试试?
试过了,不知道 Stripe 这个界面出了什么问题,但是我通过别的方法搞定了。
【引用自 未知】:
[half dead] 0 or 1美金5人头的ChatGPT Team 败家
懂了。好像现在不走原来的那个 Stripe checkout 了。退出,回到 ChatGPT 界面,用户名下面有 claim offer 从那边过去 checkout 就对了。
什么是原本的"Stripe checkout"? 我好像没见过这个东西?
就是跳转到一个 Stripe 的白底页面,左半面写价格,右半面填付款信息,右上角填邮箱如果是 Stripe 登陆过的邮箱还会让你收短信登录的那种界面。另一个是 ChatGPT 自己的有 dark mode 的 checkout 界面,付款信息填在左下角的那个。我没截图,只能这么描述了。
咦 那就很奇怪了 我还是用你说的stripe的 没有问题 那估计你被stripe单独风控了
Merchandise: Chatgpt
是很奇怪,今天出现的pending。过两天看看是不是会post
【引用自 xxxyyy】:
我privacy开过好几个号了,光昨天就俩
我记得大佬说过你是一个个手动换token,用完了一个用另外一个,为什么要一天开2个号?注册一个team就有6个token了吧
【引用自 catkinkk】:
为什么要一天开2个号?
因为我第一个被取消了
【引用自 未知】:
[half dead] 0 or 1美金5人头的ChatGPT Team 败家
对的,我昨天也发生了,想着来这个帖子说一声,转头就忘记了。
前天没问题,应该是风控升级了。
用虚拟卡就行,反正锁卡也不怕忘。不然就自己提前几天取消吧
一直没明白 citi的virtual card是可以姓名,地址,zipcode都随便用吗?我自己测试zipcode好像必须是真实的
没用过shiti 看我发帖记录你就知道我是shiti一生黑了
一个号到期再撸新号有必要手机热点注册么?用家里宽带固定IP撸多了怕IP被风控
不用zs
某书上看到封了一波team帐号,我前几天开的都还没事,不知道是IP杀还是怎么搞的
估计东8用户 用奇奇怪怪的卡开的
我强烈觉得是东8用户喜欢滥用的卡头被标记了
海鲜市场买的一个team账号已经被关了,用了不到一个星期
五个账号额度共享还是额度独立,一个号已经快爽完了
独立zs
我买了个有质保的25天内掉了4次补了4次额度重置了4次还挺爽的,就是历史信息拿不回来
小知识,你可以把号t出group拉一个新号进来,又有新额度了。这样你相当于有无限额度。但是最近开始管控了,你t号多了拉人功能会被冻结三天
所以说5个人只是五个座,只要是新来的就能获得一个满的额度
那我是不是五个都用完的过程中逐步踢人就可以了
以前可以 现在有t人冷却期
我好像像个白痴 team 5个号可以轮流蹬 每个人有自己的limit?
用的是codex的app 现在只能webpage登录 API直接没有quota
想用API方便一点 蹬的方式不对么?
救救孩子吧
【引用自 oOTTOo】:
我好像像个白痴 team 5个号可以轮流蹬 每个人有自己的limit?
对啊。
想要切换简单点,很多办法,比如用CLIProxyAPI这个项目
谢谢我研究一下(
0USD的team的API不能直接用在codex app对么?(https://platform.openai.com/api-keys)
根本不自带api,要钱的
刚买了一个 被封了 之前那个用了一个月 太爽了 用了500刀
今天新注册的用户看不到offer了
刚注册了0元新号没遇到问题
image914×530 12.6 KB
刚刚开了又看到说啥好像是two weeks only 大家想要薅羊毛的快点薅
弄会部署和登录了=-=接下来是配置claude的json
大佬是把CPA和claudecode一起用对么 效果最好?
和opencode一起用的,我不用claude
给ld这么配的,她说比codex好用
claude里怎么配置?
Claude Code | CLIProxyAPI
被封的完全是卡bin问题,用vx的开张virtual card 一点事情没有,估计其他c1卡也可以
跑个题, 用gmail新注册的chatgpt (free的,不是这个team) 都没有web search了吗? “ This chat currently doesn’t have a live web-browsing/search tool enabled , so I can only use built-in knowledge and anything you paste here.”
team额度现在好像只有plus一半了,15-60vs33-168
数字啥意思?这两天用起来确实很快就要换号,难受的皮包
上个月有 2x 的时候还没感觉。今天凌晨到现在 5 个号已经换了一轮了。不过我的用量至少 5 个号够用 5 个小时,转一圈下来又刷新了。每月 quota 不够那只能再开一个 team 了。
这个quote是多少?是每个月更新吗?
按 token 来的,具体多少不清楚。有每 5 小时的 quota 和每月的 quota 并行。也就是说在每月总量的 cap 之外还限制集中连续使用,就算月 quota 还有但是如果 5 小时内 quota 已经耗尽,要么等 5 小时之后重新刷新 quota 要么换号继续。OpenAI 倒是不会强制一个 session 必须绑定一个账号,所以就是重新登录一下而已,登录之后继续原来的 session 就好了。我记得很久之前试过 Antigravity, 那个是登录新账号就无法访问之前账号的 session 强制从头来的那种,就比较痛苦。
Claude也是这样,2个quota
感觉楼主的分享,让Codex写了一个cliproxyapi的hand on傻瓜教程,这样大家有了team的账号用cliproxyapi更加方便 #p-7957986-cliproxyapi-1CLIProxyAPI 使用指南 #p-7957986-oauth-provider-api-key-2通过 OAuth 登录后,用 Provider + API Key 调用模型 这篇主要讲 4 件事: 如何安装和启用 CLIProxyAPI 需要改哪些配置文件 如何配置多个 OAuth Token 如何通过 WebUI 查看额度 / Usage Quota #p-7957986-cliproxyapi-3一、什么是 CLIProxyAPI CLIProxyAPI 可以把你本地的 OAuth 登录能力包装成标准 API 服务。 也就是说,你先用自己的账号完成 OAuth 登录,然后 CLIProxyAPI 会在本地启动一个 API 服务。之后,任何支持自定义 Provider / Base URL / API Key 的客户端,都可以通过下面这三个信息来调用模型: Base URL Model Provider API Key 常见调用地址通常类似这样: http://127.0.0.1:8317/v1 #p-7957986-cliproxyapi-4二、如何安装和启用 CLIProxyAPI 如果你已经安装过,可以直接跳到下一步。 安装完成后,先确认版本: cliproxyapi --help 如果命令可用,就说明已经安装成功。 #p-7957986-oauth-5三、先完成 OAuth 登录 如果你是使用 Codex / ChatGPT OAuth,推荐直接用命令行登录,通常比 WebUI 更稳定: cliproxyapi -codex-login --no-browser 执行后会发生这些事: 终端输出一个登录链接 把这个链接复制到浏览器打开 登录你的 ChatGPT 账号 CLIProxyAPI 把 OAuth 凭证保存到本地 如果默认回调端口有冲突,也可以换端口: cliproxyapi -codex-login --no-browser --oauth-callback-port 1456 如果你想使用设备码方式,也可以: cliproxyapi -codex-device-login #p-7957986-cliproxyapi-6四、如何启用 CLIProxyAPI 你需要一个配置文件,例如 config.yaml 。 下面是一个基础示例: host: "127.0.0.1" port: 8317 tls: enable: false cert: "" key: "" remote-management: allow-remote: false secret-key: "YOUR_MANAGEMENT_KEY" disable-control-panel: false auth-dir: "~/.cli-proxy-api" api-keys: - "YOUR_API_KEY" debug: false usage-statistics-enabled: true proxy-url: "" force-model-prefix: false request-retry: 2 max-retry-credentials: 1 max-retry-interval: 15 ws-auth: false enable-gemini-cli-endpoint: false nonstream-keepalive-interval: 0 routing: strategy: "round-robin" 然后启动: cliproxyapi -local-model -config /path/to/config.yaml #p-7957986-cliproxyapi-7五、如何“接入” CLIProxyAPI 任何支持自定义模型服务的工具,只要支持下面这几个参数,就可以接入 CLIProxyAPI: Base URL API Key Model #p-7957986-h-8你需要提供给客户端的内容 #p-7957986-h-1-base-url-91. Base URL http://127.0.0.1:8317/v1 #p-7957986-h-2-api-key-102. API Key 就是你在 config.yaml 中配置的这一段: api-keys: - "YOUR_API_KEY" #p-7957986-h-3-model-113. Model 名称 模型名取决于 CLIProxyAPI 当前暴露出来的模型列表。 你可以用下面命令查看: curl http://127.0.0.1:8317/v1/models \ -H "Authorization: Bearer YOUR_API_KEY" 常见可选模型可能包括: gpt-5 gpt-5.4 gpt-5.3-codex 所以,本质上你只需要告诉别人: Provider / Base URL: http://127.0.0.1:8317/v1 API Key: 你配置的那个 key Model: 例如 gpt-5.4 #p-7957986-h-12六、配置文件要改哪里 CLIProxyAPI 最关键的配置位置有两个: #p-7957986-h-1-131. 主配置文件 通常是: /usr/local/etc/cliproxyapi.conf 很多情况下它其实会链接到: ~/.cli-proxy-api/config.yaml 你可以这样检查: ls -la /usr/local/etc/cliproxyapi.conf #p-7957986-h-2-oauth-142. OAuth 凭证目录 通常是: ~/.cli-proxy-api/ 这个目录里会保存你登录后的 OAuth 文件,比如 Codex、Claude、Gemini 等认证文件。 #p-7957986-h-15七、配置里最需要修改的部分 通常你主要需要修改这几项: #p-7957986-h-1-161. 监听地址和端口 host: "127.0.0.1" port: 8317 如果只想本机访问,建议用 127.0.0.1 。 #p-7957986-h-2-api-keys-172. API Keys api-keys: - "YOUR_API_KEY" 这里的 key 是给客户端调用用的,不是 OAuth Token。 如果你还没有 API Key,可以自己生成一个: openssl rand -hex 16 这会生成一个 32 位十六进制字符串。 #p-7957986-h-3-183. 管理后台密钥 remote-management: secret-key: "YOUR_MANAGEMENT_KEY" 这个 key 是 WebUI 管理后台使用的,和 api-keys 不是同一个东西。 #p-7957986-h-4-oauth-194. OAuth 凭证目录 auth-dir: "~/.cli-proxy-api" CLIProxyAPI 会从这里加载登录后的多个 OAuth Token。 #p-7957986-h-5-usage-205. Usage 统计 usage-statistics-enabled: true 如果你希望在 WebUI 中看到 usage / quota 统计,建议开启。 #p-7957986-oauth-token-21八、如何配置多个 OAuth Token CLIProxyAPI 支持加载多个 OAuth 凭证,并进行轮询或切换。 #p-7957986-oauth-token-22多个 OAuth Token 是怎么实现的? 不是在 api-keys 里写多个 OAuth Token。 真正的 OAuth 凭证通常是保存在 auth-dir 指定的目录中,也就是: ~/.cli-proxy-api/ 比如你多次登录后,目录里可能出现多个认证文件,例如: codex-account-a.json codex-account-b.json claude-account-a.json gemini-account-a.json CLIProxyAPI 启动时会自动扫描这些文件并加载。 #p-7957986-oauth-token-23如何添加多个 OAuth Token 最常见方式就是多次执行对应登录命令,用不同账号登录。 例如多次登录 Codex: cliproxyapi -codex-login --no-browser 每登录一个账号,就会在 ~/.cli-proxy-api/ 里新增一个对应的 OAuth 文件。 #p-7957986-oauth-24如何查看当前有哪些 OAuth 文件 find ~/.cli-proxy-api -maxdepth 1 -type f | sort #p-7957986-h-25多账号如何调度 配置中可以设置路由策略: routing: strategy: "round-robin" 常见可选值: round-robin fill-first round-robin 表示多个凭证轮流使用。 fill-first 表示优先吃满一个,再切换下一个。 #p-7957986-api-key-26九、如何配置多个 API Key 如果你想给多个客户端使用,也可以在 api-keys 中配置多个 key: api-keys: - "key-1" - "key-2" - "key-3" 这样不同客户端可以用不同的 API Key 访问同一个 CLIProxyAPI 服务。 注意: api-keys 是给客户端访问代理服务用的 OAuth Token 是账号登录后的认证文件 这两者不是一回事 #p-7957986-webui-usage-quota-27十、如何用 WebUI 查看 Usage Quota CLIProxyAPI 自带管理界面,可以查看认证状态、模型、日志、以及部分 Provider 的额度信息。 #p-7957986-h-1-281. 先确保服务在运行 cliproxyapi -local-model -config /path/to/config.yaml #p-7957986-h-2-webui-292. 打开 WebUI 在浏览器中访问: http://127.0.0.1:8317/management.html 或者: http://localhost:8317/management.html #p-7957986-h-3-management-key-303. 输入 Management Key 进入页面后,输入你在配置里设置的这个值: remote-management: secret-key: "YOUR_MANAGEMENT_KEY" #p-7957986-h-4-quota-314. 查看额度 / Quota 连接成功后,一般可以在 WebUI 里查看这些内容: Auth Files Models Usage Quota Management 如果是支持 quota 展示的 Provider,在对应页面里可以看到类似: Codex Quota Claude Quota Gemini CLI Quota #p-7957986-h-5-usage-quota-325. 如果看不到 Usage / Quota 请检查下面几项: #p-7957986-usage-33开启 usage 统计 usage-statistics-enabled: true #p-7957986-management-api-34Management API 没被禁用 确保 remote-management.secret-key 有值,不要留空。 #p-7957986-cliproxyapi-35使用较新的 CLIProxyAPI 版本 版本太旧时,某些 WebUI 功能可能不可用。 #p-7957986-h-36十一、如何验证当前模型可用 你可以直接请求模型列表: curl http://127.0.0.1:8317/v1/models \ -H "Authorization: Bearer YOUR_API_KEY" 如果要测试一次实际调用,也可以: curl http://127.0.0.1:8317/v1/chat/completions \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-5.4", "messages": [ { "role": "user", "content": "Say hello in one short sentence." } ] }' #p-7957986-h-37十二、最简使用方式 如果只想快速跑起来,最简单就是下面几步。 #p-7957986-h-1-codex-381. 登录 Codex cliproxyapi -codex-login --no-browser #p-7957986-h-2-392. 启动代理 cliproxyapi -local-model -config /path/to/config.yaml #p-7957986-h-3-403. 提供给客户端这三个信息 #p-7957986-base-url-41Base URL http://127.0.0.1:8317/v1 #p-7957986-api-key-42API Key YOUR_API_KEY #p-7957986-model-43Model gpt-5.4 #p-7957986-h-44十三、补充说明 #p-7957986-webui-oauth-45WebUI 登录 OAuth 为什么有时会失败? 因为 WebUI 登录除了浏览器登录本身,还多了一步“把回调结果提交回 CLIProxyAPI”的过程。 有些情况下,这一步会失败,所以命令行登录通常更稳定: cliproxyapi -codex-login --no-browser #p-7957986-webui-46命令行登录成功后,WebUI 还能用吗? 可以。 很多人会这样使用: 用命令行完成 OAuth 登录 用 WebUI 查看配置、模型、usage、quota 这是很常见也很稳定的使用方式。
为什么不直接让codex帮你配置 这些操作全都可以让codex帮你做
是让他做的,然后让他summarize了一遍
用下来还是claude+opus最强最省心,唯一就是太贵,$20的plan一周的quote我2天都不够。亲身的sonnet都差一截。接上cpa的的gpt-5.4不知道怎么样。
5.4无敌好用,fast模式也很快,token消耗高无所谓、反正无限开号=无限token
现在还能无限开号吗?我自己的号都没一个有试用
无痕模式,safari,icloud private email
找到了 原来要用专属链接
xxxyyy: icloud private email 这个我还在研究怎么弄,要订阅i cloud+?
嗯嗯,不过也可以用其他邮箱,icloud方便点而已
那是哪个teams trial 吗?
白嫖的是不是token数量明显变少啊,之前怎么用都用不完,现在随便几个简单问题改改code就30%没了
同样遇到了 stripe(右边填付款信息)就过不去 左边填信息的那个就可以
为啥我的team 在codex里面不能切换模式,只能用5.3,
是的,我最近也发现了这个问题。研究了一下之后,用量应该是砍到了前一阵的1/4到1/6。有两个因素,一个是4/2之前2x的优惠取消了,另一个是business plan暖心升级,从https://developers.openai.com/codex/pricing?codex-usage-limits=business#what-are-the-usage-limits-for-my-plan的说明来看,business的5h用量砍到了plus的1/2到1/3,而之前是和plus一样的。这个网页没有提weekly的具体的数量,不过估计比例差不多 网页里面的The number of Codex messages you can send的表格: #p-7986196-plus-1Plus Local Messages / 5h Cloud Tasks / 5h Code Reviews / week GPT-5.4 33-168 Not available Not available GPT-5.4-mini 110-560 Not available Not available GPT-5.3-Codex 45-225 10-60 10-25 #p-7986196-business-2Business Local Messages / 5h Cloud Tasks / 5h Code Reviews / week GPT-5.4 15-60 Not available Not available GPT-5.4-mini 40-200 Not available Not available GPT-5.3-Codex 20-90 5-40 15-30
闲鱼上15-20块的是用了这个方法吗?尝试弄了弄,好像也没显示是team? /uploads/short-url/cXLEfiIRkDuNVUa6EDkiSIyeMko.jpeg?dl=1
这chatgpt subscription做的这么烂吗,都收到email说cancel了,到时间了还是续费了
原来我不是一个人 找客服cancel就可以
你这个消息也过时了,你再看看,现在官网写的一样的。team = plus + 拥有pro的access /uploads/short-url/rZRZkVeiklgQZEK342IdVmOzMUe.jpeg?dl=1 /uploads/short-url/xa74EuAgYzLGtgU5Vj7IK6Yqr9Y.jpeg?dl=1
后排提醒一下,如果懒得开一堆号,只想开五个,但又想省着用token的技巧。 对于CliProxyAPI的轮训策略可以改一下 GPT的周额度只有在使用了至少一个token后才会开始倒计时7天刷新。 然后优先使用同一个账号会比不断轮训换账号有更高的cached token,token消耗更低,会省很多(我90%的token都是cache的) 最优策略 1. 每7天,使用几次round robin策略,消耗掉每个账户的1 token 2. 切换成fill first策略直到下一个七天
请问为啥一定要用掉1token?
挺好的,只是减半的话可用性还是不错的
说的很清楚啊,不开始用就不会计算七天啊
感谢,我视力越来越差了lol
是当天cancel 的吗请问 看来需要提前几天了
提前一周的,感觉是bug
今天使用了一下发现 Business 版还挺好用的,准备续费了 主要是还支持 SSO,打算把员工都加进来用 有一个坑,是免费试用只能选 5 seats,如果用了不到 5 seats,第二个月开始根据实际数量扣费
现在付款要么不成功,要么成功之后也没有 workspace 不知道什么情况。一直卡在这里 /uploads/short-url/7G5RFCJMSvUk5rwRECtjRuYsUhQ.png?dl=1 显示 invalid_workspace_selected 虽然用户显示是 business 但是无法管理 workspace 或者查看 workspace 信息。 甚至都收到 /uploads/short-url/wSdBB4x1SCQF9Zg3cBSr08NCrIY.png?dl=1 了也依旧用不了……再等等,如果过几个小时还有问题那我还是及时取消吧,省得下个月真 charge 了还完全没用过那就搞笑了。
害怕的去新注册了一个账户,一样的情况,希望是服务器的问题而不是要寄了
然后发现从 manage subscription 进去根本没法取消订阅啊,难绷。这次 privacy 卡一直下单不了,只好改用的 Citi virtual card 但是据说 subscription 管不了?在想办法至少看看能不能在这个界面再换成 privacy 卡。
我也是citi的虚拟卡,但citi不是可以设置25刀的上限吗,应该问题不是特别大
Em……之前听说有 C1 的虚拟卡关卡后还被 subscription 扣款的来着,不清楚这个 spending limit 是不是个 hard limit 还是也只有第一次 authorize 的时候 enforce 之后随缘。不过刚才测试在 manage subscription 那个网页可以改成 Privacy card, 我还是改了,图个安心。
Update: 一顿操作自己吓自己之后,发现 workspace 能登录了……
之前也卡过,不管他,直接登陆gpt聊天的界面就好了,然后在那管理。
不是,这次显然更严重些。GPT 界面根本无法切换到 workspace 也无从管理。 /uploads/short-url/beM2416YGUWekxjlmvZDLa1VBMX.png?dl=1
我下午开了个新号也遇到了,还以为是citi虚拟卡被秒封 等两个小时就好了
regular的free chatgpt也是这样的吗?
应该一样的
好像直接用fill first也不损失什么?有多个的话,一个用完了到下一个的时候如果离上次用已经7天的话第一次就reset了?
henry: 一个用完了到下一个的时候如果离上次用已经7天的话第一次就reset了? 不是的,每个账户单独reset。 如果你直接fill first什么都不管,等于其他账户还没被用的一直在损失免费的额度。 除非你一周连一个账户都没用完,不然就血亏
我一次发了5张图片,直接卡死。 API rate limit reached. Please try again later.
xxxyyy: GPT的周额度只有在使用了至少一个token后才会开始倒计时7天刷新 周额度是每7天还是每周? 用了一个token 就开始倒计时,那就应该尽快先用这个?
wpzh: 周额度是每7天还是每周? 开始倒计时后的第七天,跟日历无关 wpzh: 用了一个token 就开始倒计时,那就应该尽快先用这个? 用还没开始倒计时的。不触发倒计时 = token扔水里
今天刚开了个新号 http://mozmail.com 不能用了 上个月可以 网页版 最新只能看到5.3 codex能用5.4
今天用privacy的卡开新号被decline了,不知道是不是因为我同一个商户刷太多,系统不让我搞了(privacy之前就这样不允许我刷uber) 换了一张我自己的amex,用的公寓地址 + 第二行数字乱写,过了
似乎有点死了。“Sorry, you’re not eligible for this promotional discount.”,怎么改无痕切VPN也没用
同 不知道是不是新号的原因
没登陆账号就显示Sorry, you’re not eligible for this promotional discount吗 /uploads/short-url/ekaA3lu2ZOYreL3X1l6Xue8zr1w.png?dl=1
手机safari无痕模式,不需要VPN
/uploads/short-url/3yCQvKGV61f2coMBHq95WbV6Ybe.jpeg?dl=1 登陆了的
你登陆了肯定没有呀,要新用户的。用那个试用链接注册才行
好的 感谢 我之前都是登陆了也行 再试试
我试了 也还是没有优惠
还真是,我试了试,好像也没了,难道DEAD了吗
https://help.openai.com/en/articles/20001000-chatgpt-business-free /uploads/short-url/7vTSxB5MZvbXbyxN5twgdusYlHx.png?dl=1 我看到这个,用了日本ip gmail注册 ,只有plus的free一个月。team还是没有。按这个说的话还是要work email 才有。不过这三个月之前更新的 /uploads/short-url/xtfN4VZe3hLgQjy7EYo49lg9ZuS.jpeg?dl=1 /uploads/short-url/cGVrg8EoUSBqqLvQape6YipUvsV.jpeg?dl=1
/uploads/short-url/fN1Ua76WGzWcCIagRnUrLqIwvLn.jpeg?dl=1 域名邮箱没问题的 你们不会用什么gmail之类注册的吧
域名邮箱咋搞,只能买吗
对 要自己买域名 cloudflare可以免费托管邮箱 直接转发到你设置邮箱里面
买一个域名,能无限创建邮箱?创建邮箱还要付费吗
用cloudflare的话他是catch all 任何邮箱@域名都会直接转发给你 不用钱
/uploads/short-url/csCHpJp7j73eZMQZOcU8mr0Gqfh.png?dl=1 链接打开的时候有Sorry, you’re not eligible for this promotional discount 但是用自己的域名邮箱注册后成功0试用
急需amex credit顶上
namecheap 上有很多1块钱管一年的域名
换了一堆卡都过不了,privacy也不行
用Amex真实卡,新地址JIT
域名邮箱也不行 /uploads/short-url/wZ5UOnFISCaKxGlZ0pIB2SVBByo.jpeg?dl=1
看域名的 刷不出来你这个域名就废了
还没出呢吧
今天被封了第一个号
咋还会被封号,干啥了
估计是因为加了几个其他账户的workspace
我都是每次把过期的workspace清理掉的,退了之后才加新的
是不是其余4个副号可以不变,每次重新申请主号。但是需要在前主号里面删掉4个副号,再在新的主号里面添加
我是这么做的。也可以自己去副号里退掉
到订阅结束的时候提前取消就不会被直接取消了 另外问,用自己的相同域名邮箱会不会在开第二个月的时候有麻烦,邮箱地址可以做到完全不同
not eligible 咋办
我本来下个月6号到期,刚才取消马上就不能使用了。
gmail开的也成功了?然后四个副号用同一个gmail加号大法就好
刚才用邮箱大法申请新的账号,一直报错:existing_user 难道这个办法已经被屏蔽了?
好像真的无了。换了邮箱进去,只有20%off了
我还剩两天取消的还能继续用,是我忽悠了你吗 对不起对不起
可能每个人都不一样,我第一次刚注册好就取消也能用一个月。
https://www.azx.us/posts/700 https://www.azx.us/posts/700 探索在Android模拟器上利用Frida工具绕过Google Play Billing,实现ChatGPT订阅优惠激活的详细教程。无需实际付费,轻松获取免费试用和优惠档位,帮助开发者和用户实现订阅破解。 这个可刑?
现在取消就不能用了
能啊,我还剩两天取消了一直在用,账号是挂在cpa里的
似乎被Sam干掉了,只能用新注册账号一个月的Plus
新设备也not eligible 看来只能闲鱼了 xxxyyy: safari无痕模式
域名邮箱
但点了链接还没创建账号,左下角就not eligible /uploads/short-url/rQBrWKzuuaJbd3TkovsMFaWgtE4.jpeg?dl=1
照样注册 域名没问题注册后照样可以
卡是同名同地址没问题么
貌似一个地址只能两次
我们说的是物理地址(家庭住址)么 为什么是 第一个 地址,我没太理解
typo
那只能暂住邻居家几分钟了
team不够蹬 被迫需要这个策略了 但是我可不想手动 让codex写了一个脚本使用token 脚本代码 #!/usr/bin/env python3 from __future__ import annotations import argparse import json import os import sys import time import urllib.error import urllib.parse import urllib.request from dataclasses import dataclass from typing import Any SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) DEFAULT_CONFIG_FILE = os.path.join(SCRIPT_DIR, "config.json") DEFAULT_SERVER_BASE_URL = "http://127.0.0.1:8317" DEFAULT_MODEL = "gpt-5.4-mini" DEFAULT_PREFIX_PREFIX = "quota" DEFAULT_TRIGGER_THRESHOLD_SECONDS = 30 DEFAULT_RECENT_TRIGGER_GRACE_SECONDS = 900 DEFAULT_STATE_FILE_NAME = "state.json" MANAGEMENT_PREFIX = "/v0/management" CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage" CODEX_USER_AGENT = "codex_cli_rs/0.76.0 (Debian 13.0.0; x86_64) WindowsTerminal" MODEL_PREFIX_WAIT_SECONDS = 10.0 MODEL_PREFIX_POLL_INTERVAL_SECONDS = 0.5 class ScriptError(RuntimeError): pass @dataclass class AuthFile: name: str auth_index: str account_id: str email: str | None status: str | None @dataclass class WindowState: label: str limit_seconds: int reset_after_seconds: int | None needs_trigger: bool @dataclass class TriggerState: triggers: dict[str, int] @dataclass class RuntimeConfig: server_base_url: str management_key: str api_key: str model: str prefix_prefix: str trigger_threshold_seconds: int recent_trigger_grace_seconds: int state_file: str def normalize_string(value: Any) -> str | None: if isinstance(value, str): trimmed = value.strip() return trimmed or None if isinstance(value, (int, float)) and not isinstance(value, bool): return str(value) return None def normalize_int(value: Any) -> int | None: if isinstance(value, bool): return None if isinstance(value, int): return value if isinstance(value, float): return int(value) if isinstance(value, str): trimmed = value.strip() if not trimmed: return None try: return int(float(trimmed)) except ValueError: return None return None def first_present(*values: Any) -> Any: for value in values: if value is not None: return value return None def classify_window(limit_seconds: int, fallback: str) -> str: if limit_seconds == 18000: return "5h" if limit_seconds == 604800: return "weekly" return fallback def format_reset_after(reset_after_seconds: int | None) -> str: if reset_after_seconds is None: return "unknown" if reset_after_seconds < 60: return f"{reset_after_seconds}s" minutes, seconds = divmod(reset_after_seconds, 60) if minutes < 60: return f"{minutes}m{seconds:02d}s" hours, minutes = divmod(minutes, 60) if hours < 24: return f"{hours}h{minutes:02d}m" days, hours = divmod(hours, 24) return f"{days}d{hours:02d}h" def resolve_relative_path(path: str, base_dir: str) -> str: if os.path.isabs(path): return path return os.path.join(base_dir, path) def load_json_file(path: str, description: str) -> Any: try: with open(path, "r", encoding="utf-8") as handle: return json.load(handle) except FileNotFoundError as exc: raise ScriptError(f"{description} file not found: {path}") from exc except json.JSONDecodeError as exc: raise ScriptError(f"{description} file is not valid JSON: {path}") from exc except OSError as exc: raise ScriptError(f"failed to read {description} file: {path}: {exc}") from exc def read_required_string(value: Any, field_name: str) -> str: normalized = normalize_string(value) if normalized: return normalized raise ScriptError(f"config field {field_name} is required") def read_int_with_default(value: Any, default_value: int, field_name: str) -> int: if value is None: return default_value normalized = normalize_int(value) if normalized is None or normalized < 0: raise ScriptError(f"config field {field_name} must be a non-negative integer") return normalized def load_runtime_config(config_path: str, args: argparse.Namespace) -> RuntimeConfig: payload = load_json_file(config_path, "config") if not isinstance(payload, dict): raise ScriptError(f"config file must contain a JSON object: {config_path}") config_dir = os.path.dirname(config_path) def pick(name: str, cli_value: Any, default_value: Any = None) -> Any: if cli_value is not None: return cli_value if name in payload: return payload[name] return default_value server_base_url = normalize_string(pick("server_base_url", args.server_base_url, DEFAULT_SERVER_BASE_URL)) if not server_base_url: server_base_url = DEFAULT_SERVER_BASE_URL server_base_url = server_base_url.rstrip("/") management_key = read_required_string(pick("management_key", args.management_key), "management_key") api_key = read_required_string(pick("api_key", args.api_key), "api_key") model = normalize_string(pick("model", args.model, DEFAULT_MODEL)) or DEFAULT_MODEL prefix_prefix = normalize_string(pick("prefix_prefix", args.prefix_prefix, DEFAULT_PREFIX_PREFIX)) or DEFAULT_PREFIX_PREFIX trigger_threshold_seconds = read_int_with_default( pick("trigger_threshold_seconds", args.trigger_threshold_seconds), DEFAULT_TRIGGER_THRESHOLD_SECONDS, "trigger_threshold_seconds", ) recent_trigger_grace_seconds = read_int_with_default( pick("recent_trigger_grace_seconds", args.recent_trigger_grace_seconds), DEFAULT_RECENT_TRIGGER_GRACE_SECONDS, "recent_trigger_grace_seconds", ) state_file_value = normalize_string(pick("state_file", args.state_file, DEFAULT_STATE_FILE_NAME)) or DEFAULT_STATE_FILE_NAME state_file = resolve_relative_path(state_file_value, config_dir) return RuntimeConfig( server_base_url=server_base_url, management_key=management_key, api_key=api_key, model=model, prefix_prefix=prefix_prefix, trigger_threshold_seconds=trigger_threshold_seconds, recent_trigger_grace_seconds=recent_trigger_grace_seconds, state_file=state_file, ) def load_trigger_state(path: str) -> TriggerState: try: with open(path, "r", encoding="utf-8") as handle: payload = json.load(handle) except FileNotFoundError: return TriggerState(triggers={}) except (OSError, json.JSONDecodeError): return TriggerState(triggers={}) raw_triggers = payload.get("triggers") if not isinstance(raw_triggers, dict): return TriggerState(triggers={}) triggers: dict[str, int] = {} for key, value in raw_triggers.items(): auth_index = normalize_string(key) timestamp = normalize_int(value) if auth_index and timestamp and timestamp > 0: triggers[auth_index] = timestamp return TriggerState(triggers=triggers) def save_trigger_state(path: str, state: TriggerState) -> None: parent = os.path.dirname(path) if parent: os.makedirs(parent, exist_ok=True) payload = {"version": 1, "triggers": state.triggers} temp_path = f"{path}.tmp" with open(temp_path, "w", encoding="utf-8") as handle: json.dump(payload, handle, sort_keys=True) os.replace(temp_path, path) def sanitize_prefix_prefix(value: str) -> str: cleaned = [] for char in value.lower(): if char.isalnum() or char in {"-", "_"}: cleaned.append(char) else: cleaned.append("-") prefix = "".join(cleaned).strip("-_") return prefix or "quota" def planned_prefix(prefix_prefix: str, auth_index: str) -> str: return f"{sanitize_prefix_prefix(prefix_prefix)}-{auth_index[:8]}" def detect_existing_prefix(model_ids: list[str]) -> tuple[str | None, list[str]]: base_model_ids = {model_id for model_id in model_ids if "/" not in model_id} prefixes: set[str] = set() for model_id in model_ids: if "/" not in model_id: continue prefix, suffix = model_id.split("/", 1) if not prefix: continue if not base_model_ids or suffix in base_model_ids: prefixes.add(prefix) ordered = sorted(prefixes) return (ordered[0] if ordered else None), ordered def build_window_states(usage_payload: dict[str, Any], threshold_seconds: int) -> list[WindowState]: rate_limit = usage_payload.get("rate_limit") or usage_payload.get("rateLimit") or {} if not isinstance(rate_limit, dict): return [] now = int(time.time()) raw_windows = [ ("primary", rate_limit.get("primary_window") or rate_limit.get("primaryWindow")), ("secondary", rate_limit.get("secondary_window") or rate_limit.get("secondaryWindow")), ] window_states: list[WindowState] = [] for fallback_label, raw_window in raw_windows: if not isinstance(raw_window, dict): continue limit_seconds = normalize_int( first_present( raw_window.get("limit_window_seconds"), raw_window.get("limitWindowSeconds"), ) ) if not limit_seconds or limit_seconds <= 0: continue reset_after_seconds = normalize_int( first_present( raw_window.get("reset_after_seconds"), raw_window.get("resetAfterSeconds"), ) ) if reset_after_seconds is None: reset_at = normalize_int(first_present(raw_window.get("reset_at"), raw_window.get("resetAt"))) if reset_at is not None: reset_after_seconds = max(0, reset_at - now) window_states.append( WindowState( label=classify_window(limit_seconds, fallback_label), limit_seconds=limit_seconds, reset_after_seconds=reset_after_seconds, needs_trigger=( reset_after_seconds is not None and reset_after_seconds >= max(0, limit_seconds - threshold_seconds) ), ) ) return window_states class CPAClient: def __init__(self, server_base_url: str, management_key: str, api_key: str, timeout_seconds: int = 60) -> None: self.server_base_url = server_base_url.rstrip("/") self.management_base_url = self.server_base_url + MANAGEMENT_PREFIX self.management_key = management_key self.api_key = api_key self.timeout_seconds = timeout_seconds def _request_json( self, method: str, url: str, headers: dict[str, str] | None = None, payload: dict[str, Any] | None = None, ) -> Any: request_headers = dict(headers or {}) data = None if payload is not None: data = json.dumps(payload).encode("utf-8") request_headers.setdefault("Content-Type", "application/json") request = urllib.request.Request(url, data=data, headers=request_headers, method=method) try: with urllib.request.urlopen(request, timeout=self.timeout_seconds) as response: raw_body = response.read().decode("utf-8", errors="replace") except urllib.error.HTTPError as exc: raw_body = exc.read().decode("utf-8", errors="replace") detail = raw_body.strip() or exc.reason raise ScriptError(f"{method} {url} failed: HTTP {exc.code} {detail}") from exc except urllib.error.URLError as exc: raise ScriptError(f"{method} {url} failed: {exc.reason}") from exc if not raw_body.strip(): return {} try: return json.loads(raw_body) except json.JSONDecodeError as exc: raise ScriptError(f"{method} {url} returned non-JSON data: {raw_body[:300]}") from exc def _management_headers(self) -> dict[str, str]: return {"Authorization": f"Bearer {self.management_key}"} def get_force_model_prefix(self) -> bool: payload = self._request_json( "GET", self.management_base_url + "/force-model-prefix", headers=self._management_headers(), ) return bool(payload.get("force-model-prefix")) def list_codex_auth_files(self) -> list[AuthFile]: payload = self._request_json( "GET", self.management_base_url + "/auth-files", headers=self._management_headers(), ) files = payload.get("files") if not isinstance(files, list): raise ScriptError("management auth-files response is missing files") auth_files: list[AuthFile] = [] for item in files: if not isinstance(item, dict): continue provider = normalize_string(first_present(item.get("provider"), item.get("type"))) if provider != "codex": continue if bool(item.get("disabled")): continue auth_index = normalize_string(first_present(item.get("auth_index"), item.get("authIndex"))) name = normalize_string(item.get("name")) if not auth_index or not name: continue id_token = item.get("id_token") account_id = None if isinstance(id_token, dict): account_id = normalize_string( first_present(id_token.get("chatgpt_account_id"), id_token.get("chatgptAccountId")) ) if not account_id: continue auth_files.append( AuthFile( name=name, auth_index=auth_index, account_id=account_id, email=normalize_string(item.get("email")), status=normalize_string(item.get("status")), ) ) return auth_files def get_auth_models(self, name: str) -> list[str]: query = urllib.parse.urlencode({"name": name}) payload = self._request_json( "GET", self.management_base_url + f"/auth-files/models?{query}", headers=self._management_headers(), ) models = payload.get("models") if not isinstance(models, list): raise ScriptError(f"management auth-files/models response is missing models for {name}") model_ids: list[str] = [] for item in models: if not isinstance(item, dict): continue model_id = normalize_string(item.get("id")) if model_id: model_ids.append(model_id) return model_ids def query_codex_usage(self, auth_index: str, account_id: str) -> dict[str, Any]: payload = self._request_json( "POST", self.management_base_url + "/api-call", headers=self._management_headers(), payload={ "auth_index": auth_index, "method": "GET", "url": CODEX_USAGE_URL, "header": { "Authorization": "Bearer $TOKEN$", "Content-Type": "application/json", "User-Agent": CODEX_USER_AGENT, "Chatgpt-Account-Id": account_id, }, }, ) status_code = normalize_int(first_present(payload.get("status_code"), payload.get("statusCode"))) if status_code is None or status_code < 200 or status_code >= 300: body = normalize_string(payload.get("body")) or "" raise ScriptError(f"quota query failed for auth_index={auth_index}: HTTP {status_code or 0} {body[:300]}") body = payload.get("body") if isinstance(body, str): try: decoded = json.loads(body) except json.JSONDecodeError as exc: raise ScriptError(f"quota query returned invalid JSON for auth_index={auth_index}") from exc if isinstance(decoded, dict): return decoded elif isinstance(body, dict): return body raise ScriptError(f"quota query returned an unexpected body for auth_index={auth_index}") def patch_auth_prefix(self, name: str, prefix: str) -> None: self._request_json( "PATCH", self.management_base_url + "/auth-files/fields", headers=self._management_headers(), payload={"name": name, "prefix": prefix}, ) def warm_model(self, model_id: str) -> dict[str, Any]: response = self._request_json( "POST", self.server_base_url + "/v1/messages", headers={ "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json", "anthropic-version": "2023-06-01", }, payload={ "model": model_id, "max_tokens": 1, "messages": [{"role": "user", "content": "hi"}], }, ) if not isinstance(response, dict): raise ScriptError(f"warmup call returned an unexpected response for model {model_id}") return response def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="Trigger Codex quota windows in CLIProxyAPI when they are unfixed.") parser.add_argument("--config", default=DEFAULT_CONFIG_FILE) parser.add_argument("--server-base-url") parser.add_argument("--management-key") parser.add_argument("--api-key") parser.add_argument("--model") parser.add_argument("--prefix-prefix") parser.add_argument("--trigger-threshold-seconds", type=int) parser.add_argument("--recent-trigger-grace-seconds", type=int) parser.add_argument("--state-file") parser.add_argument("--dry-run", action="store_true") parser.add_argument("--verbose", action="store_true") return parser.parse_args() def log(message: str, *, verbose: bool, always: bool = False, error: bool = False) -> None: if not always and not verbose: return stream = sys.stderr if error else sys.stdout print(message, file=stream) def ensure_prefix( client: CPAClient, auth_file: AuthFile, model: str, prefix_prefix: str, verbose: bool, dry_run: bool, ) -> tuple[str, bool]: model_ids = client.get_auth_models(auth_file.name) existing_prefix, all_prefixes = detect_existing_prefix(model_ids) if len(all_prefixes) > 1: raise ScriptError( f"{auth_file.name} exposes multiple prefixes ({', '.join(all_prefixes)}); unable to pick a unique route" ) if existing_prefix: return existing_prefix, False next_prefix = planned_prefix(prefix_prefix, auth_file.auth_index) if dry_run: return next_prefix, True client.patch_auth_prefix(auth_file.name, next_prefix) deadline = time.time() + MODEL_PREFIX_WAIT_SECONDS while time.time() < deadline: model_ids = client.get_auth_models(auth_file.name) existing_prefix, _ = detect_existing_prefix(model_ids) if existing_prefix == next_prefix or f"{next_prefix}/{model}" in model_ids: log( f"set-prefix name={auth_file.name} prefix={next_prefix}", verbose=verbose, always=True, ) return next_prefix, True time.sleep(MODEL_PREFIX_POLL_INTERVAL_SECONDS) raise ScriptError(f"{auth_file.name} prefix update did not become visible in time") def main() -> int: args = parse_args() try: runtime_config = load_runtime_config(os.path.abspath(args.config), args) except ScriptError as exc: log(str(exc), verbose=args.verbose, always=True, error=True) return 1 client = CPAClient( server_base_url=runtime_config.server_base_url, management_key=runtime_config.management_key, api_key=runtime_config.api_key, ) checked = 0 triggered = 0 failures = 0 trigger_state = load_trigger_state(runtime_config.state_file) try: if client.get_force_model_prefix(): log( "warning force-model-prefix=true; adding a prefix changes how unprefixed model requests route", verbose=args.verbose, always=True, error=True, ) auth_files = client.list_codex_auth_files() except ScriptError as exc: log(str(exc), verbose=args.verbose, always=True, error=True) return 1 for auth_file in auth_files: checked += 1 try: usage_payload = client.query_codex_usage(auth_file.auth_index, auth_file.account_id) window_states = build_window_states(usage_payload, runtime_config.trigger_threshold_seconds) trigger_windows = [window for window in window_states if window.needs_trigger] if not trigger_windows: if args.verbose: window_summary = ", ".join( f"{window.label}={format_reset_after(window.reset_after_seconds)}" for window in window_states ) or "none" log(f"skip name={auth_file.name} windows={window_summary}", verbose=True) continue now = int(time.time()) last_trigger_at = trigger_state.triggers.get(auth_file.auth_index) if ( last_trigger_at is not None and now - last_trigger_at < max(0, runtime_config.recent_trigger_grace_seconds) ): remaining = runtime_config.recent_trigger_grace_seconds - (now - last_trigger_at) log( f"skip-recent name={auth_file.name} last_trigger={format_reset_after(remaining)}", verbose=args.verbose, always=args.verbose, ) continue prefix, prefix_added = ensure_prefix( client=client, auth_file=auth_file, model=runtime_config.model, prefix_prefix=runtime_config.prefix_prefix, verbose=args.verbose, dry_run=args.dry_run, ) model_ids = client.get_auth_models(auth_file.name) target_model = f"{prefix}/{runtime_config.model}" if target_model not in model_ids and runtime_config.model not in model_ids: raise ScriptError(f"{auth_file.name} does not expose model {runtime_config.model}") reason = ",".join( f"{window.label}:{format_reset_after(window.reset_after_seconds)}" for window in trigger_windows ) action = "set-prefix,warmup" if prefix_added else "warmup" if args.dry_run: log( f"would-trigger name={auth_file.name} reason={reason} prefix={prefix} model={target_model} action={action}", verbose=args.verbose, always=True, ) continue warm_response = client.warm_model(target_model) response_id = normalize_string(warm_response.get("id")) or "-" returned_model = normalize_string(warm_response.get("model")) or "-" log( f"triggered name={auth_file.name} reason={reason} prefix={prefix} model={target_model} " f"response_id={response_id} upstream_model={returned_model} action={action}", verbose=args.verbose, always=True, ) triggered += 1 trigger_state.triggers[auth_file.auth_index] = int(time.time()) save_trigger_state(runtime_config.state_file, trigger_state) except ScriptError as exc: failures += 1 log(f"error name={auth_file.name} message={exc}", verbose=args.verbose, always=True, error=True) if args.verbose or triggered > 0 or failures > 0 or args.dry_run: log( f"summary checked={checked} triggered={triggered} failures={failures} dry_run={str(args.dry_run).lower()}", verbose=args.verbose, always=True, error=failures > 0, ) return 1 if failures > 0 else 0 if __name__ == "__main__": sys.exit(main()) crontab ( sudo crontab -e ): 0 * * * * 脚本 >> /var/log/cpa_trigger_quota.log 2>&1 每小时执行一次 参考config.json { "server_base_url": "http://127.0.0.1:8317", "management_key": "你的密码", "api_key": "你的API_KEY", "model": "gpt-5.4-mini", "prefix_prefix": "quota", "trigger_threshold_seconds": 30, "recent_trigger_grace_seconds": 900, "state_file": "state.json" }
CliProxyAPI不是可以设置session-affinity的吗,我理解把ttl设长一些一个session就pin到一个账号了,不会在同session里反复切换账号,这样直接round robin就可以?
我其实想把key和账号绑定在一起。这样应该是最好的。 不过只是coding的话fill first肯定是最佳的,也不用设置什么了
注册了为什么没给我零元购,直接就是$125
域名废了 下一个
/uploads/short-url/uVau92M6jJo856G8yDAU5I7YYPL.png?dl=1 这是域名废了? 可是换普通域名注册非 Business 账户也一样失败是什么情况啊?
这看起来像是被封号了
/uploads/short-url/8uZpBnapDIAYA9mtFsdhckO1mlM.png?dl=1 感觉是开始封服务器 IP 了。看来只能把 CLIProxyAPI 放到本地了。同域名新号没有 team 的活动,只有 plus 了,就随便开了一个先用着吧。还是和上次一样的付款策略,先用 Citi 的 virtual card 以假名+假地址付款,然后在 billing 页添加 Privacy 并删除 Citi. 毕竟月费低于 Citi 的最小 spending limit 了,还是这么整放心点。
这个CLIProxyAPI里面的账号怎么判断已经被掐了还是只是额度被限制用不了?
好像全DEAD了
配额管理里会显示当前额度的,刷新凭证后可以看到。没额度显示0%,被封号了会显示错误
去Linux do看了一圈,这个渠道应该是彻底关闭了。现在没有办法白嫖team了。接下来只能等amex biz plat的报销了
Failed to load quota: 401 Your authentication token has been invalidated. Please try signing in again. 这种就是被封了? 前几天才注册的,应该一次也没有用过
被封号了你这是
啊啊啊啊啊啊啊真的是如丧考妣啊
oai的trial有人被反薅过吗 懒得用虚拟卡
自己记得取消怎么被反薅
free plus用privacy怎么都过不去
privacy半个月前就寄了
坏了,也是卡在了试用过期前死了
国内有人搞的那种按api收费的网站划算吗
有的会降智,有的cache miss rate高,有的会混一些烂模型注水,有的没隐私,有的不稳定三天两头用不了。各有各的问题。而且都不能用5.5 pro这种nb模型。渠道基本都是各种免费试用的日抛plus 用的多还是直接开官方pro比较好
确定是dead了吗 28号 c1的billing信息乱填都过了
28号晚上dead的,其他论坛有很多人讨论过了
找到了https://linux.do/t/topic/2077223/34 只要plus试用还在就问题不大,只不过原来一张c1虚拟卡能开6个号,现在要开6张卡
https://www.uscardforum.com/t/topic/502565 /c/shopping/20 https://efficient.app/deals/chatgpt L站看到的deal。 众所周知,OpenAI因为财务紧张,开始疯狂杀各种free trial渠道。现在ChatGPT已有的免费渠道几乎死光了。 不过有人发现有个网站和openai有分销活动,承诺4年半价。25刀每个月可以买两个gpt team席位(等于plus的额度 + 可以使用pro模型),保持四年不变。 结合马上要… 我打算用这个deal了,过一段时间结合biz plat就可以白嫖了,还不用每个月单独搞
hivechian: 只要plus试用还在就问题不大 这个也死了,linux do的号基本被杀光了。新开的也是一天就杀
为什么会被杀的
因为这些哥们都是vpn节点?
team到期了,没看到plus free试用的入口,需要新注册账号才能看到吗?
Plus 前天开的,暂时还没问题,我把 CLIProxyAPI 部署到本地了,不知道会不会好点。
https://chatgpt.com/?promoCode=STRIPEPERKSGPT4BIZ 这个链接试了好几种邮箱都不行,现在只有个人的plus试用了
已经又DEAD了
然后还没用呢就被杀了 /uploads/short-url/9k1kBHqmTGvYfCaHXNXdeEfLGRN.png?dl=1
我的域名账号刚刚也被杀了
plus是这样的,最近杀疯了,号都是日抛
上周刚开的team也是
是开完就取消了嘛,我同时薅了plus和team的域名邮箱还健在
没取消啊,就刚刚突然收到deactivate的邮件。
我上个月试用完的号被杀了,肯定被当成gamer了
感觉和服务器 IP 没什么关系了。要么是感觉新号就直接试用不太合理?也许稍微用用再试用会好些吧。
privacy 不能用了咋整 没有citi……难受
claude的pro有什么折扣码
目前没听过这回事