代理是从平台侧发起连接的,不是从你的电脑出去 —— 请用用户名 + 密码认证,IP 白名单会连不上。 如果你的代理商只支持白名单,请联系客服获取需要放行的出口 IP。
· 取票 —— 换一张 Adobe Firefly 会话票据,用来调 Firefly 出图(说明)
· 打码 —— 验证码识别,逐类型文档
机器可读版本:/openapi.json(OpenAPI 3.0)
取票是什么 / 用来干什么
x-arp-session-id)。它只服务于 Adobe Firefly 的图像生成接口 ——
你要调 Firefly 出图,请求头里必须带这张票,不带会被直接拒(HTTP 408)。
它关联的是哪个服务
| 项 | 说明 |
|---|---|
| 目标服务 | Adobe Firefly 的图像生成接口
https://firefly-3p.ff.adobe.io/v2/3p-images/generate-async |
| 用途 | 调用 Firefly 上挂载的第三方图像模型出图,例如 Gemini Nano Banana 系列、GPT-Image 系列等 |
| 票据形态 | 一个 Base64 字符串,由四段拼成:base64url({"sid":…,"ftr":…,"ark":…,"bfp":…})分别来自页面的 mcid_guid、以及 forter / arkose / bfp 三个风控 cookie |
| 怎么用 | 放进请求头 x-arp-session-id,出口走取票时返回的同一个代理 |
为什么要单独"取"一张票
这张票是 Adobe 风控体系(Forter / Arkose / 浏览器指纹)签发的, 没法用代码凭空造出来,必须在真实浏览器环境里、从住宅 IP 出口跑一遍页面才能采集到。
所以平台把它做成了服务:你用接口取票,我们负责最麻烦的那一步。
你需要自备什么
- 一个住宅代理 —— 票绑定铸票时的出口 IP,所以必须由你提供(见下方代理规则)
- 一个 Adobe 账号 的
access_token—— 票和账号无关,但调 Firefly 要用你的账号授权
三步接入
- 在请求里带上你的代理模板(含
{sid}占位符)—— 见下节。 也可以先在控制台「代理配置」里存一份,之后就不必每次带。 - 调
POST /v1/ticket?async=1受理一个取票任务,拿到job_id。 - 轮询
GET /v1/ticket/{job_id}直到status=ready, 从result里拿proxy_url+ticket。 - 用这个
proxy_url作为出口,把ticket放进请求头x-arp-session-id,去请求 Adobe 生图接口。
/openapi.json 里的 pure 1~2 秒 指的是纯铸票耗时,
加上排队/加密,服务端 2–3 秒就绪)。
但客户端实际拿到的时延取决于你的轮询节奏:默认 poll_after_sec=3,
所以实测端到端 4–6 秒(冷启动偶发 9 秒)。
只有在纯算连续失败、退回浏览器方案时才需要 100–150 秒(最坏约 6 分钟)。
同步请求得一直挂着这条连接,链路上任何一层代理的空闲超时都会把它掐断 ——
而掐断不等于失败:票可能已经铸出来、积分也扣了,你却什么都没拿到,
只能重试、再扣一次。异步只依赖你的耐心,不依赖任何中间层的超时配置。
代理模板怎么传(三种方式,任选其一)
| 方式 | 写法 | 适用 |
|---|---|---|
| 请求头(最简单) | X-Proxy-Template: http://...sid-{sid}...:密码@host:port |
不改 body 就能带 |
| 请求体 | {"proxy_template": "http://...sid-{sid}..."} |
已经在发 JSON 的客户端 |
| 控制台预设 | 「代理配置」里保存一次,之后自动使用 | 固定用一个代理的长期用户 |
推荐用请求参数:代理是你的资源,凭据不必先存进我们库里才能用 —— 带参数是无状态的,少一次"先配置再取票"的前置步骤。
代理模板怎么写(不绑定任何厂商)
模板就是一串普通的代理 URL,里面用 {sid} 作为占位符。
铸票时服务端会把它替换成 12 位随机字母数字,用它开出一个「粘性会话」,
并把替换后的完整 URL 作为 proxy_url 返回给你。
① URL 里有
{sid}(位置随厂商而定,见下表);② 这串
{sid} 能让代理保持同一个出口 IP(粘性会话)至少几十秒。没有粘性会话的代理(每次请求换 IP)一定失败 —— 票绑定铸票那一刻的出口。
常见厂商的写法(把你自己的账号密码替换进去即可):
| 厂商 | 模板写法 | {sid} 位置 |
|---|---|---|
| Bright Data | http://用户名-session-{sid}:密码@brd.superproxy.io:22225 | 用户名里 |
| Oxylabs | http://用户名-sess-{sid}:密码@pr.oxylabs.io:7777 | 用户名里 |
| Decodo / Smartproxy | http://用户名-session-{sid}:密码@gate.smartproxy.com:7000 | 用户名里 |
| IPRoyal | http://用户名:密码_session-{sid}@geo.iproyal.com:12321 | 密码里 |
| 1024proxy | http://用户名-region-US-sid-{sid}-t-360:密码@us.1024proxy.io:3000 | 用户名里 |
| 自建 / 通用 | http://用户名:密码@你的代理:端口 + 会话参数 | 看你的实现 |
US → 200,GB/DE/NL → 408。
原因是指纹与出口的地理一致性:我们的指纹池里
fe.TO 全是 420(美国太平洋时区)、fe.L 是 en-US、
fe.PK 是 Win32。若从欧洲 IP 提交,
Adobe 看到的是"一台美国时区的 Windows 电脑从欧洲发起请求",地理上不可能,
于是回 408 system under load —— 而这个响应体
和"票不合格"、"号废了"完全一样,极难区分。
所以模板请用
region-US,不要用 GB/DE/NL。
-t-30 / sessionduration /
_lifetime …)。默认粘性窗口太短会导致提交时 IP 已经变了,票作废。
建议 ≥ 60 秒,因为提交生图要 15–20 秒。
{region} 是可选项 ——
想固定某个国家就在模板里写死(如 region-US),
不想写就让代理自己分配。本站默认不强制地区。
认证
两种凭证,任一即可:
| 方式 | 写法 | 用于 |
|---|---|---|
| API Key | Authorization: Bearer arp_xxx | 程序调用(推荐) |
| 会话 Cookie | arp_session=…(登录后自动下发) | 浏览器页面 |
也支持查询串 ?key=arp_xxx,但不推荐 —— Key 会进访问日志和 Referer。
接口列表
对外集成请一律使用 /v1/*。/api/* 是本站前端自用,随页面改动,不保证兼容。
| 方法 | 路径 | 说明 | 扣费 |
|---|---|---|---|
| POST | /v1/ticket?async=1 | 取票(异步受理),返回 job_id | 受理即冻结 |
| GET | /v1/ticket/{job_id} | 轮询任务;ready 时连票一起返回 | — |
| GET | /v1/ticket/jobs | 我最近的取票任务(刷新/重启后接着看) | — |
| DELETE | /v1/ticket/{job_id} | 取消进行中的任务,预扣全额退回 | — |
| POST | /v1/ticket | 取票(同步,兼容保留) | 成功才扣 |
| GET | /v1/tickets | 使用日志:最近 20 次取票明细 | — |
| GET | /v1/me | 账号信息与用量 | — |
| GET | /v1/credits | 积分余额(含批次明细) | — |
| GET | /v1/credits/ledger | 积分流水 | — |
| GET | /v1/proxy | 读取代理模板(密码打码) | — |
| PUT | /v1/proxy | 设置代理模板 | — |
| GET | /v1/keys | 列出 API Key | — |
| POST | /v1/keys | 新建 API Key | — |
| POST | /v1/redeem | 兑换码充值 | — |
| GET | /v1/captcha/prices | 打码价格表 | — |
| POST | /v1/captcha/solve | 打码识别(同步) | 成功才扣 |
| POST | /v1/captcha/task | 打码识别(异步建任务) | 成功才扣 |
| GET | /v1/captcha/task/{id} | 查询异步结果 | — |
| GET | /healthz | 健康检查(免认证) | — |
取票 POST /v1/ticket?async=1
取票分两步:受理任务,然后轮询结果。
第 1 步必须带上你的代理模板(X-Proxy-Template 头,
或请求体的 {"proxy_template":"..."})—— 铸票要用你的代理出口。
第 1 步:受理任务
curl -X POST 'https://api.xiaobaicap.com/v1/ticket?async=1' \
-H "Authorization: Bearer arp_xxx" \
-H "X-Proxy-Template: http://用户名-region-US-sid-{sid}-t-360:密码@us.1024proxy.io:3000"
{sid},且这串 {sid} 能让代理保持同一个出口 IP
(粘性会话)至少 60 秒。没有粘性会话的代理一定失败。
也可以在控制台「代理配置」里存一次,之后就不必每次带。
响应 202(积分此时已被冻结,不是扣掉):
{
"ok": true,
"job_id": "9f2c41ab77e04d3f8b6a1c5e",
"status": "queued",
"stage": "queued",
"message": "已受理,正在等空闲的铸票通道",
"price": 0,
"balance": 3100,
"poll_url": "/v1/ticket/9f2c41ab77e04d3f8b6a1c5e",
"poll_after_sec": 3,
"expires_in_sec": 86400
}
0,不扣费)。
网络超时后拿不准有没有受理成功,就先
GET /v1/ticket/jobs 看看有没有刚建的任务,别直接重发。
第 2 步:轮询直到出票
GET https://api.xiaobaicap.com/v1/ticket/9f2c41ab77e04d3f8b6a1c5e
Authorization: Bearer arp_xxx
轮询是免费的,按 poll_after_sec(3 秒)的节奏来即可,不要打满。
进行中长这样:
{
"ok": true, "job_id": "9f2c41ab…", "status": "running",
"stage": "token",
"message": "正在换取安全校验 token(纯算主路径,通常 1–2 秒)",
"attempt": 1, "attempts": 3,
"elapsed_sec": 1, "price": 0, "balance": 3100,
"poll_after_sec": 3
}
status | 含义 | 该怎么办 |
|---|---|---|
queued | 已受理,等空闲的铸票通道 | 继续轮询 |
running | 正在铸票,看 stage 知道进行到哪一步 | 继续轮询 |
ready | 出票了,积分已真扣 | 取 result 里的票去用 |
failed | 铸票失败,积分已全额退回(看 refunded) | 可以重新受理,建议退避 3–5 秒 |
canceled | 你主动取消,积分已全额退回 | — |
stage 是稳定的阶段标识。纯算路径通常是
queued(排队)→ token(换 Arkose token)→ done;
只有退回浏览器方案时才会看到 browser(启动浏览器)→ page(打开页面)
→ waiting(等安全校验,最久的一段)。
任何路径都可能出现 retry(换出口重试)。
注意:ready 之后 stage 字段整个不存在(不是空字符串)——
终态只看 status,别拿 stage 判完成。
取值请用 resp.get("stage"),直接 resp["stage"] 会 KeyError。
elapsed_sec 让你能确认任务确实在推进,而不是卡死了。
message 只是给人看的一句话,别拿它做判断。
ready 的响应(result 就是一张完整的票):
{
"ok": true, "job_id": "9f2c41ab…", "status": "ready",
"elapsed_sec": 128, "done_at": "2026-10-13T09:02:28Z",
"result": {
"id": 12,
"sid": "2dd7c978-65bd-4ea2-98fd-0efef4734b31",
"ticket": "eyJhcmsiOiIyNzYxOGRlMGI1MTcwOGQ3OC4...",
"proxy_url": "http://用户名-session-rh4qpqfo3ge5:密码@你的代理域名:端口",
"minted_at": "2026-10-13T09:02:28Z",
"took_sec": 1,
"price": 0,
"balance": 3100,
"next_expire_at": "", // 空 = 长期有效(不过期)
"usage": "用 proxy_url 作为出口、把 ticket 放进请求头 x-arp-session-id …"
}
}
| 字段 | 说明 |
|---|---|
sid | 票里的会话 UUID(= ticket 解码后的 sid 段)。它不是代理会话 ID —— 代理会话是 proxy_url 里那串 12 位字符(如 b60vlc27geoj),两者不同。复用出口只认 proxy_url,拿 sid 拼代理地址会失败 |
ticket | 票据本体,直接放进请求头 x-arp-session-id |
proxy_url | 必须用这个出口提交,不能换成别的代理。只有它能复现铸票时的出口 IP |
price / balance | 本次扣费与扣后余额。price 是站点当前定价,由运营在后台配置,0 = 免费;示例里的数值只是举例,不要写死 |
next_expire_at | 最近一批积分的到期时间。空字符串 = 长期有效 |
failed 不要直接放弃。
任务丢了怎么办 / 任务列表
进程重启、客户端崩了、job_id 没存下来 —— 用这个接口把最近的任务捞回来:
GET https://api.xiaobaicap.com/v1/ticket/jobs?limit=20
Authorization: Bearer arp_xxx
{"ok":true,"active":1,"max_active":2,
"jobs":[{"job_id":"9f2c41ab…","status":"running","stage":"token",
"price":0,"created_at":"2026-10-13T09:00:20Z","elapsed_sec":1}]}
failed 并
立刻退回预扣积分,所以轮询不会看到一个永远不动的 running。
每人在进行中的任务最多 2 个,到顶回 429 too_many_jobs(不会扣费)。
取消任务
DELETE https://api.xiaobaicap.com/v1/ticket/9f2c41ab77e04d3f8b6a1c5e
Authorization: Bearer arp_xxx
{"ok":true,"job_id":"9f2c41ab…","status":"canceling","canceled":true,
"message":"已请求取消,预扣积分随即全额退回"}
取消是幂等的:任务已经结束时会返回现状(canceled:false)而不是报错。
极少数情况下任务已经铸成、正在收尾,取消失败会如实回 409 conflict
—— 这时别当成已退费,继续轮询到终态为准。
同步调用(兼容保留)
POST /v1/ticket 不带 ?async=1 时仍会一直等你到出票
(200,字段就是上面那个 result)。
新接入不建议再用它:它要求客户端超时 ≥ 300 秒,而且中间任何一层代理
提前断开,你都会陷入"不知道到底扣没扣费"的状态。
Prefer: respond-async 是等效的异步写法(HTTP 标准头),
用现成 SDK 时比加查询串方便。
打码服务 POST /v1/captcha/solve
除了取票,平台还提供验证码识别:reCaptcha V2/V3(含企业版)、hCaptcha、 Cloudflare Turnstile / 5 秒盾、以及各类图像识别。按次扣积分,识别失败全额退回。
先看价格
curl https://api.xiaobaicap.com/v1/captcha/prices -H "Authorization: Bearer arp_xxx"
{"default":4,"price":{"ImageToTextTaskMuggle":4,"NoCaptchaTaskProxyless":25,
"TurnstileTaskProxyless":42,...}}
单价按任务复杂度分档,约 4 ~ 50 积分。具体见 GET /v1/captcha/prices。
以接口实时返回为准,这里不列死数字。
同步识别(推荐)
curl -X POST 'https://api.xiaobaicap.com/v1/captcha/solve?timeout=180' \
-H "Authorization: Bearer arp_xxx" \
-H 'Content-Type: application/json' \
-d '{
"type": "NoCaptchaTaskProxyless",
"websiteURL": "https://example.com",
"websiteKey": "6Lc..."
}'
成功返回 200:
{
"ok": true,
"task_id": "3e286ed2-c6e9-11f1-b1fb-525400737fb0",
"ready": true,
"took_ms": 6402,
"price": 10,
"balance": 990,
"solution": { "token": "0.xxxxx", "userAgent": "Mozilla/5.0 ..." },
"token": "0.xxxxx",
"text": "",
"objects": null,
"cookies": {}
}
token / text / objects / cookies
是按任务类型抽好的便捷字段,原始结构在 solution 里。
异步(任务多时用)
# 1) 建任务(会扣费)
POST /v1/captcha/task {"type":"TurnstileTaskProxyless","websiteURL":"...","websiteKey":"..."}
# → {"ok":true,"task_id":"...","ready":false}
# 2) 轮询(免费)
GET /v1/captcha/task/{task_id}
# → {"ready":false,"status":"processing"} … 直到 {"ready":true,...}
支持的任务类型
| type | 说明 | 主要参数 |
|---|---|---|
NoCaptchaTaskProxyless | reCAPTCHA v2 | websiteURL websiteKey,选填 isInvisible userAgent |
RecaptchaV2EnterpriseTaskProxyless | reCAPTCHA v2 Enterprise | websiteURL websiteKey,选填 enterprisePayload isInvisible userAgent |
RecaptchaV3TaskProxyless | reCAPTCHA v3 | websiteURL websiteKey,选填 pageAction minScore |
RecaptchaV3EnterpriseTask | reCAPTCHA v3 Enterprise | websiteURL websiteKey,选填 pageAction minScore enterprisePayload |
HCaptchaTaskProxyless | hCaptcha | websiteURL websiteKey,选填 userAgent isInvisible rqdata |
TurnstileTaskProxyless | Cloudflare Turnstile | websiteURL websiteKey,选填 action cData userAgent |
CloudFlareTaskS2 | Cloudflare 5 秒盾 | websiteURL proxy,选填 userAgent waitLoad requiredCookies |
ImageToTextTaskMuggle | 图片 OCR(ImageToText) | body |
ReCaptchaV2Classification | reCAPTCHA v2 图像识别 | image question |
HCaptchaClassification | hCaptcha 图像识别 | queries question,选填 anchors |
FunCaptchaClassification | FunCaptcha 图像识别 | image question |
AwsClassification | AWS WAF 图像识别 | queries question |
bCaptchaClassification | bCaptcha 图像识别 | queries question |
FunCaptchaTask | FunCaptcha 协议版 | websiteURL websitePublicKey data userAgent proxyType proxyAddress proxyPort,选填 funcaptchaApiJSSubdomain proxyLogin proxyPassword |
FunCaptchaTaskProxyless | FunCaptcha 协议版(不带代理) | websiteURL websitePublicKey data userAgent,选填 funcaptchaApiJSSubdomain |
NoCaptchaTask | reCAPTCHA v2(自带代理) | websiteURL websiteKey proxyType proxyAddress proxyPort,选填 isInvisible userAgent proxyLogin proxyPassword |
RecaptchaV2EnterpriseTask | reCAPTCHA v2 Enterprise(自带代理) | websiteURL websiteKey proxyType proxyAddress proxyPort,选填 enterprisePayload userAgent proxyLogin proxyPassword |
HCaptchaTask | hCaptcha(自带代理) | websiteURL websiteKey proxyType proxyAddress proxyPort,选填 userAgent isInvisible rqdata proxyLogin proxyPassword |
TurnstileTask | Cloudflare Turnstile(自带代理) | websiteURL websiteKey proxyType proxyAddress proxyPort,选填 action cdata proxyLogin proxyPassword |
RecaptchaV2TaskProxyless | reCAPTCHA v2(同族命名) | websiteURL websiteKey,选填 isInvisible userAgent |
RecaptchaV3TaskProxylessM1 | reCAPTCHA v3 · M1 | websiteURL websiteKey,选填 pageAction userAgent |
RecaptchaV3TaskProxylessM1S7 | reCAPTCHA v3 · M1S7(强制评分 0.7) | websiteURL websiteKey,选填 pageAction userAgent |
RecaptchaV3EnterpriseTaskM1 | reCAPTCHA v3 Enterprise · M1 | websiteURL websiteKey,选填 pageAction enterprisePayload |
ImageToTextTaskM1 | 图片 OCR · M1 | body |
ImageToTextTask | 图片 OCR(旧命名) | body |
data:image/xxx;base64, 前缀都行,网关会统一处理。
请求体里只写本页列出的业务参数,认证与其它字段由网关处理。
拿到票之后怎么用
POST https://firefly-3p.ff.adobe.io/v2/3p-images/generate-async
authorization: Bearer <你自己的 Adobe access_token>
x-api-key: clio-playground-web
x-arp-session-id: <上面拿到的 ticket>
x-nonce: sha256(adobe_user_id + "-" + prompt[:256])
content-type: application/json
出口:必须走上面那个 proxy_url
proxy_url(proxy_url 里的那个 sid 相同 → 同一个出口 IP)提交。
注意:不要用响应里的 result.sid 去拼代理地址 —— 那是票里的会话 UUID,
和代理会话 ID 是两回事,只认 proxy_url 原串。
换了出口 = 票作废,Adobe 会回 408 system under load。
另外:票是从匿名会话铸出来的,和 Adobe 账号无关 —— 一张票可以给不同账号用。你需要自备账号的
access_token。
完整 Python 示例
import hashlib, time, requests
BASE = "https://api.xiaobaicap.com"
KEY = "arp_xxx"
PROXY = None # 取票后填
def get_ticket(timeout=600):
"""受理一个取票任务并轮询到出票。失败会抛异常(不扣费)。"""
h = {"Authorization": f"Bearer {KEY}"}
r = requests.post(f"{BASE}/v1/ticket?async=1", headers=h, timeout=30)
r.raise_for_status()
job = r.json()
deadline = time.time() + timeout
wait = job.get("poll_after_sec", 3)
while time.time() < deadline:
time.sleep(wait)
s = requests.get(f"{BASE}/v1/ticket/{job['job_id']}", headers=h, timeout=30).json()
if s["status"] == "ready":
return s["result"]
if s["status"] in ("failed", "canceled"):
raise RuntimeError(s.get("error") or s["status"])
raise TimeoutError(f"取票超时(job {job['job_id']})")
t = get_ticket()
proxies = {"http": t["proxy_url"], "https": t["proxy_url"]}
prompt = "a red apple on a white marble table"
uid = "你的 Adobe user_id"
nonce = hashlib.sha256(f"{uid}-{prompt[:256]}".encode()).hexdigest()
r = requests.post(
"https://firefly-3p.ff.adobe.io/v2/3p-images/generate-async",
headers={
"authorization": f"Bearer {ACCESS_TOKEN}",
"x-api-key": "clio-playground-web",
"x-arp-session-id": t["ticket"],
"x-nonce": nonce,
"content-type": "application/json",
},
proxies=proxies, timeout=60,
json={
"modelId": "gemini-flash",
"modelVersion": "nano-banana-2026-09",
"n": 1,
"prompt": prompt,
"resolution": "1K",
"output": {"storeInputs": True},
"generationSettings": {"aspectRatio": "1:1"},
})
print(r.status_code, r.text[:200])
错误码
所有错误响应形状固定:
{"error": "人类可读的描述", "code": "机器可读的稳定标识"}
请按 code 分支,不要匹配 error 文案 —— 文案会调整,code 不会。
| HTTP | code | 含义 | 该怎么处理 |
|---|---|---|---|
| 400 | bad_request | 参数或请求体不合法 | 改代码,别重试 |
| 400 | proxy_not_configured | 本次请求没带代理,账号里也没存过 | 加 X-Proxy-Template 头,或带 {"proxy_template":"..."} |
| 401 | unauthorized | 没带凭据或 Key 无效/被停用 | 检查 Key,别重试 |
| 402 | insufficient_credits | 积分不足(已拦下,未扣费) | 充值后重试 |
| 403 | forbidden | 凭据有效但权限不够 | 换账号,别重试 |
| 404 | not_found | 资源不存在(含不是你的取票任务) | 别重试 |
| 409 | conflict | 当前状态不允许这个操作(如取消一个已在收尾的任务) | 轮询到终态为准 |
| 429 | rate_limited | 触发限流 | 按 Retry-After 退避 |
| 429 | too_many_jobs | 进行中的取票任务已达上限(未扣费) | 等已有任务结束,或先取消 |
| 502 | mint_failed | 铸票失败(已全额退回) | 可重试,建议退避 3–5 秒 |
| 500 | internal_error | 服务端内部错误 | 可重试,仍失败请反馈 |
502。你的调用方对 502 / 429 / 500
做 2–3 次指数退避重试即可,不用担心重复扣费(失败全额退回)。
限流与超时
| 项 | 值 | 说明 |
|---|---|---|
| 普通接口限流 | 120 次/分钟/IP | 超了回 429 + Retry-After |
| 登录/注册限流 | 10 次/分钟/IP | 与普通接口分开计量 |
| 取票耗时 | 服务端纯算 1–3 秒就绪;客户端实测 4–6 秒(默认轮询间隔 3 秒,冷启动偶发 ~9 秒);退回浏览器方案时 100–150 秒(最坏 ~6 分钟) | 用异步入口就不必关心超时;同步入口建议客户端超时 ≥ 60 秒 |
| 取票轮询 | 建议 3 秒一次(poll_after_sec) | 轮询免费,但计入普通接口限流 |
| 同时进行的取票任务 | 每账号最多 2 个 | 超了回 429 too_many_jobs,不扣费 |
| 取票任务记录 | 保留 24 小时 | 过期后查询回 404;票本身在用票日志里 |
| 打码耗时 | 协议类 10–60 秒,图像类 1–5 秒 | 客户端超时建议 ≥ 120 秒 |
| 返回的票有效期 | 建议铸出后 尽快使用 | 票会随会话老化,放久了会 408,需重新取票 |
| 积分有效期 | 长期有效(不过期) | next_expire_at 返回空字符串即表示不过期 |
稳定性约定
- 所有响应带
X-API-Version: 1。把它记进你的日志,排查"升级后行为变了"时一眼看出。 /v1/*是冻结契约:字段只增不改不删。破坏性变更走/v2。- 新增响应字段是可能发生的,所以请忽略你不认识的字段,不要做严格校验。
- 错误码是稳定枚举;新增错误码会在此页和 /openapi.json 同步。
- 幂等性:
GET和DELETE /v1/ticket/{job_id}全部幂等, 轮询随便打。POST /v1/ticket不是幂等的 —— 每受理成功一次就铸一张新票(当前票价0,实际不扣费);但失败一定不扣费, 所以failed之后重试是安全的。网络超时后拿不准有没有受理成功时, 先查GET /v1/ticket/jobs,别直接重发。
常见问题
受理返回 429 too_many_jobs
你已经有 2 个取票任务在进行中。等它们结束(轮询到 ready / failed),
或者 DELETE /v1/ticket/{job_id} 主动取消一个。这个拒绝不会扣费。
轮询一直停在 running 不动
先看 elapsed_sec 有没有在涨(在涨就是正常推进)。纯算通常几秒内完成;
只有 stage=browser / waiting 时才可能拖到几分钟。
过了十几分钟还是 running,基本是那次部署重启把它打断了 —— 重新
GET 一次任务即可看到终态。服务重启会把中断的任务标成
failed 并立刻退回预扣积分。
提交时一直回 408 system under load
- 最常见:提交用的出口和取票时的出口不是同一个。必须原样使用返回的
proxy_url。 - 其次:代理模板里没带粘性参数(
-t-30之类),导致出口 IP 每次都在变。 - 再其次:票放太久了,重新取一张。
提交回 403 access_error
不是票的问题,是你这个 Adobe 账号当时不能生成(额度用尽或资格异常)。换个账号。
提交回 401 Invalid or expired token
你的 Adobe access_token 本身无效或过期了,跟票无关。重新签一个。
怎么判断一个 Adobe 账号还能不能用?
只能真提交一次看返回码。权益查询接口(feature-auth)完全不可信 ——
已失效的账号在上面一样显示 authorized / quota_available、额度一分没动,
但提交一律 408。
一张票能重复用吗?
票与账号无关,短期内可以给不同账号复用几次;但它是会话派生物,会老化失效。 要稳定出图就按需取票,不要长期囤票。
我只想拿票,不想自己接 Adobe 怎么办?
本服务只出票。出图需要你自备 Adobe 账号(access_token)并自行调用 Adobe 接口。