A

接口文档

API 能力平台 · API v1 · 契约冻结,字段只增不改
控制台
⚠️ 自带代理时,请用「用户名 + 密码」认证,不要开 IP 白名单。
代理是从平台侧发起连接的,不是从你的电脑出去 —— 请用用户名 + 密码认证,IP 白名单会连不上。 如果你的代理商只支持白名单,请联系客服获取需要放行的出口 IP。
平台提供两类能力:
· 取票 —— 换一张 Adobe Firefly 会话票据,用来调 Firefly 出图(说明)
· 打码 —— 验证码识别,逐类型文档
机器可读版本:/openapi.json(OpenAPI 3.0)

取票是什么 / 用来干什么

一句话:「取票」取的是 Adobe Firefly 的会话票据(接口里叫 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 要用你的账号授权
取票是开发者向的能力,界面上没有入口,请按下方的接口调用。 需要图形界面就能用的,请用打码服务。

三步接入

  1. 在请求里带上你的代理模板(含 {sid} 占位符)—— 见下节。 也可以先在控制台「代理配置」里存一份,之后就不必每次带。
  2. 调 POST /v1/ticket?async=1 受理一个取票任务,拿到 job_id。
  3. 轮询 GET /v1/ticket/{job_id} 直到 status=ready, 从 result 里拿 proxy_url + ticket。
  4. 用这个 proxy_url 作为出口,把 ticket 放进请求头 x-arp-session-id,去请求 Adobe 生图接口。
为什么取票是异步的:本站默认走纯算铸票,实测 1–3 秒就能出票 (/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 Datahttp://用户名-session-{sid}:密码@brd.superproxy.io:22225用户名里
Oxylabshttp://用户名-sess-{sid}:密码@pr.oxylabs.io:7777用户名里
Decodo / Smartproxyhttp://用户名-session-{sid}:密码@gate.smartproxy.com:7000用户名里
IPRoyalhttp://用户名:密码_session-{sid}@geo.iproyal.com:12321密码里
1024proxyhttp://用户名-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 KeyAuthorization: Bearer arp_xxx程序调用(推荐)
会话 Cookiearp_session=…(登录后自动下发)浏览器页面

也支持查询串 ?key=arp_xxx,但不推荐 —— Key 会进访问日志和 Referer。

API Key 只在创建时完整显示一次。泄漏了就立刻在控制台停用并重建。

接口列表

对外集成请一律使用 /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}]}
任务记录保留 24 小时。服务重启时,中断的任务会被标成 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说明主要参数
NoCaptchaTaskProxylessreCAPTCHA v2websiteURL websiteKey,选填 isInvisible userAgent
RecaptchaV2EnterpriseTaskProxylessreCAPTCHA v2 EnterprisewebsiteURL websiteKey,选填 enterprisePayload isInvisible userAgent
RecaptchaV3TaskProxylessreCAPTCHA v3websiteURL websiteKey,选填 pageAction minScore
RecaptchaV3EnterpriseTaskreCAPTCHA v3 EnterprisewebsiteURL websiteKey,选填 pageAction minScore enterprisePayload
HCaptchaTaskProxylesshCaptchawebsiteURL websiteKey,选填 userAgent isInvisible rqdata
TurnstileTaskProxylessCloudflare TurnstilewebsiteURL websiteKey,选填 action cData userAgent
CloudFlareTaskS2Cloudflare 5 秒盾websiteURL proxy,选填 userAgent waitLoad requiredCookies
ImageToTextTaskMuggle图片 OCR(ImageToText)body
ReCaptchaV2ClassificationreCAPTCHA v2 图像识别image question
HCaptchaClassificationhCaptcha 图像识别queries question,选填 anchors
FunCaptchaClassificationFunCaptcha 图像识别image question
AwsClassificationAWS WAF 图像识别queries question
bCaptchaClassificationbCaptcha 图像识别queries question
FunCaptchaTaskFunCaptcha 协议版websiteURL websitePublicKey data userAgent proxyType proxyAddress proxyPort,选填 funcaptchaApiJSSubdomain proxyLogin proxyPassword
FunCaptchaTaskProxylessFunCaptcha 协议版(不带代理)websiteURL websitePublicKey data userAgent,选填 funcaptchaApiJSSubdomain
NoCaptchaTaskreCAPTCHA v2(自带代理)websiteURL websiteKey proxyType proxyAddress proxyPort,选填 isInvisible userAgent proxyLogin proxyPassword
RecaptchaV2EnterpriseTaskreCAPTCHA v2 Enterprise(自带代理)websiteURL websiteKey proxyType proxyAddress proxyPort,选填 enterprisePayload userAgent proxyLogin proxyPassword
HCaptchaTaskhCaptcha(自带代理)websiteURL websiteKey proxyType proxyAddress proxyPort,选填 userAgent isInvisible rqdata proxyLogin proxyPassword
TurnstileTaskCloudflare Turnstile(自带代理)websiteURL websiteKey proxyType proxyAddress proxyPort,选填 action cdata proxyLogin proxyPassword
RecaptchaV2TaskProxylessreCAPTCHA v2(同族命名)websiteURL websiteKey,选填 isInvisible userAgent
RecaptchaV3TaskProxylessM1reCAPTCHA v3 · M1websiteURL websiteKey,选填 pageAction userAgent
RecaptchaV3TaskProxylessM1S7reCAPTCHA v3 · M1S7(强制评分 0.7)websiteURL websiteKey,选填 pageAction userAgent
RecaptchaV3EnterpriseTaskM1reCAPTCHA v3 Enterprise · M1websiteURL websiteKey,选填 pageAction enterprisePayload
ImageToTextTaskM1图片 OCR · M1body
ImageToTextTask图片 OCR(旧命名)body
Base64 带不带 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
票绑定铸票那一刻的出口 IP。我们用你配的代理出口铸票,所以你必须用同一个 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 不会。

HTTPcode含义该怎么处理
400bad_request参数或请求体不合法改代码,别重试
400proxy_not_configured本次请求没带代理,账号里也没存过加 X-Proxy-Template 头,或带 {"proxy_template":"..."}
401unauthorized没带凭据或 Key 无效/被停用检查 Key,别重试
402insufficient_credits积分不足(已拦下,未扣费)充值后重试
403forbidden凭据有效但权限不够换账号,别重试
404not_found资源不存在(含不是你的取票任务)别重试
409conflict当前状态不允许这个操作(如取消一个已在收尾的任务)轮询到终态为准
429rate_limited触发限流按 Retry-After 退避
429too_many_jobs进行中的取票任务已达上限(未扣费)等已有任务结束,或先取消
502mint_failed铸票失败(已全额退回)可重试,建议退避 3–5 秒
500internal_error服务端内部错误可重试,仍失败请反馈
铸票是概率性的,502 属于正常现象。我们内部会自动换出口重试若干次, 仍失败才回 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 接口。