要点
在 Rendergrid API 里,批量生成就是发送许多个独立的请求:一次请求生成一张图片。要记录每一个请求,需要三样东西。你这一侧的队列按账号的限额控制节奏:每分钟 120 次请求,队列中或处理中的任务共 100 个。Webhook 在任务结束时通知你的地址,轮询只作备用。幂等键(请求头 X-Idempotency-Key)让重试更安全:用它重试已被接收的请求,得到的是同样的响应,而不是第二张图片和第二次扣费。
批量请求 是怎么工作的?
批量生成没有单独的接口:需要多少张图片,就发送多少个请求。每个被接收的请求都会得到 202 和一个任务 id,意思是“请求已接收”,而不是“图片已就绪”。
一次请求,一张图片。需要更多图片,就发送更多请求,每个请求使用不同的幂等键。
结果稍后才有。任务经过
queued和processing,最后变成completed或failed。保存的时间有限。结果文件只保存一天,保存的幂等响应有效期为 30 天。
下面三张图是一批商品目录图片的示意:一支白色软管,三种背景,每条提示词对应一次请求。三张图都由 Nano Banana 2.1 生成,1K,1:1,各一次尝试。它们只是示例,不是测量,说明不了批量的速度和可靠性。
第一个请求的提示词
素白软管配光滑盖子,立在桃色台面上,后方是一块同色拱形板。正面拍摄,左侧柔光,阴影向右。软管居中完整,约占画面高度一半,布景宽松统一。不出现文字、标志、人物或水印。
Nano Banana 2.1
nano-banana-2.1 · 1K · 1:1 · $0.02
Nano Banana 2.1,1K,1:1,一次尝试。白色软管盖子朝下立着,顶端是带细纹的压扁封口,盖子表面光滑。软管水平居中,整体低于画面中心,高度约占画面的一半;身后立着一块桃色拱形板,左右居中,下边缘落在台面上。光从左边来,阴影投向右侧:拱形板上有一块深色阴影,台面上有一道拖向画面右缘的长阴影。画面中没有文字、标志、人物或水印。与提示词的出入:提示词要求软管居中,而软管的垂直位置低于画面中心;提示词写的是柔光,而拱形板上的阴影和台面上的长阴影边缘都较清晰。
第二个请求的提示词
白色光面软管带简洁盖子,置于桃色平台上,旁边是同色浅台阶。正面机位,柔光从左来,影子向右。软管完整居中,约占画面高度一半,台阶位于侧面不遮挡主体。不出现文字、标志、人物或水印。
Nano Banana 2.1
nano-banana-2.1 · 1K · 1:1 · $0.02
Nano Banana 2.1,1K,1:1,一次尝试。光面白色软管盖子朝下,立在画面下方的桃色平台上,软管左侧有明显的高光。软管水平居中,垂直方向也大致居中。右侧是几级浅桃色台阶,向右逐级升高,靠近软管的右缘,但没有挡住软管。光从左边来,软管的阴影向右落在平台上。盖子正面有一个小凹口,提示词没有提到。画面中没有文字、标志、人物或水印。与提示词的出入:软管高度约占画面的五分之三,提示词要求的是一半;提示词写的是柔光,而台阶上的阴影和软管在平台上的阴影边缘都较清晰。
第三个请求的提示词
桃色台面中央立着白色素面软管,配光滑瓶盖。背后同色圆盘竖立,稍偏向一侧。沿用正面视角、左侧柔光和向右阴影。软管完整,约占画面高度一半,周围留白。不出现文字、标志、人物或水印。
Nano Banana 2.1
nano-banana-2.1 · 1K · 1:1 · $0.02
Nano Banana 2.1,1K,1:1,一次尝试。白色软管盖子朝下立在桃色台面中央,身后立着一个桃色圆盘,圆心比软管略偏右,被软管遮住一部分。光从左边来,台面上向右拖出两道长长的阴影。软管水平居中,垂直方向也大致居中,四周留有空白。盖子正面有一个圆弧形凹口。墙面是偏灰的浅粉色;画面右上角有一小块深色阴影,提示词没有提到。画面中没有文字、标志、人物或水印。与提示词的出入:软管高度约占画面的五分之三,提示词要求的是一半;提示词写的是光滑的瓶盖,而盖子上有凹口;提示词写的是柔光,而台面上拖向右侧的两道长阴影边缘都较清晰。
三张图没有处处照着提示词来,所以批量流程里要留出验收这一步:队列和 Webhook 只负责送达结果,不判断它合不合用。
如何建立队列, 才不会超出限额?
队列放在你这一侧:待办的操作存在队列里,向 API 发送多少,取决于它此刻能接收多少。账号有两项相关的限额:
- 每分钟 120 次请求。启动生成、上传文件、读取模型目录和读取余额都计入,超出时返回
429 ERR_RATE_LIMIT。 - 队列中或处理中的任务共 100 个,超出时返回
429 ERR_QUOTA_EXCEEDED。
轮询不计入每分钟的请求数,它有单独的规则:同一个任务、同一个 API 密钥,每 5 秒最多查询一次,否则同样会得到 429。
队列要做三件事:
- 只在进行中的任务明显少于 100 个时才启动新任务,并且每分钟不超过 120 次。
- 遇到
429时,等待不少于Retry-After的时间,再加一点随机延迟,并限制尝试次数。 - 遇到
401、402或403时停下来,先排除原因:API 密钥错误、账号被停用、余额不足或月度限额用尽。
import os import time from collections import deque import requests API = "https://api.rendergrid.io/ api/ public/ v1" HEADERS = {"Authorization": f"Bearer {os.environ['RENDERGRID_API_KEY']}"} MAX_IN_FLIGHT = 80 # 留出余量:账号最多同时有 100 个任务 SUBMIT_PAUSE = 1.0 # 两次启动之间隔 1 秒:每分钟最多 60 次,低于 120 次的限额 POLL_PAUSE = 5.0 # 同一个任务两次查询之间至少隔 5 秒 MAX_ATTEMPTS = 5 # 一个操作最多发送几次 def retry_after(response, default=5): value = response.headers.get("Retry-After", "") return int(value) if value.isascii() and value.isdigit() else default prompts = ["……", "……"] # 你的提示词 queue = deque((f"batch-7-{n:04d}", prompt) for n, prompt in enumerate(prompts)) failures = {} # 操作编号 -> 没有得到结果的尝试次数 running = {} # 任务 id -> [操作编号, 上次查询的时间] finished = {} # 操作编号 -> GET /creations/ {id} 的响应 next_launch = 0.0 while queue or running: now = time.monotonic() if queue and len(running) < MAX_IN_FLIGHT and now >= next_launch: operation, prompt = queue[0] next_launch = now + SUBMIT_PAUSE try: r = requests.post( f"{API}/images/generate", headers={**HEADERS, "X-Idempotency-Key": operation}, json={ "model": "nano-banana-2.1", "prompt": prompt, "resolution": "1K", "aspect_ratio": "1:1", }, timeout=(5, 30), ) except (requests.Timeout, requests.ConnectionError): r = None # 没有响应,但请求可能已经送达:下次用同一个幂等键再发 if r is not None and r.status_code == 202: running[r.json()["id"]] = [operation, now] queue.popleft() elif r is not None and r.status_code == 429: next_launch = now + max(SUBMIT_PAUSE, retry_after(r)) elif r is not None and r.status_code < 500: raise RuntimeError(f"HTTP {r.status_code}: {r.text}") # 400、401、402、403、404:先排除原因 else: failures[operation] = failures.get(operation, 0) + 1 if failures[operation] >= MAX_ATTEMPTS: raise RuntimeError(f"{operation}: 多次没有得到结果,请先查看请求记录") for creation_id, state in list(running.items()): if now - state[1] < POLL_PAUSE: continue state[1] = now try: r = requests.get(f"{API}/creations/{creation_id}", headers=HEADERS, timeout=(5, 20)) except (requests.Timeout, requests.ConnectionError): continue if r.status_code == 429 or r.status_code >= 500: continue r.raise_for_status() creation = r.json() if creation["status"] in ("completed", "failed"): finished[state[0]] = creation del running[creation_id] time.sleep(0.2) failed = [name for name, c in finished.items() if c["status"] == "failed"] print(len(finished) - len(failed), "个已完成;失败的:", failed)
// Node.js 22+,文件扩展名为 .mjs const API = "https://api.rendergrid.io/ api/ public/ v1"; const AUTH = { Authorization: `Bearer ${process.env.RENDERGRID_API_KEY}` }; const MAX_IN_FLIGHT = 80; // 留出余量:账号最多同时有 100 个任务 const SUBMIT_PAUSE = 1000; // 毫秒:每分钟最多 60 次,低于 120 次的限额 const POLL_PAUSE = 5000; // 同一个任务两次查询之间至少隔 5 秒 const MAX_ATTEMPTS = 5; // 一个操作最多发送几次 const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); const noAnswer = (error) => error instanceof TypeError || error.name === "TimeoutError"; const retryAfter = (response, fallback = 5) => { const value = response.headers.get("Retry-After"); return value && /^[0-9]+$/.test(value) ? Number(value) : fallback; }; const prompts = ["……", "……"]; // 你的提示词 const queue = prompts.map((prompt, n) => ({ operation: `batch-7-${String(n).padStart(4, "0")}`, prompt, })); const failures = new Map(); // 操作编号 -> 没有得到结果的尝试次数 const running = new Map(); // 任务 id -> { operation, polledAt } const finished = new Map(); // 操作编号 -> GET /creations/ {id} 的响应 let nextLaunch = 0; while (queue.length || running.size) { const now = Date.now(); if (queue.length && running.size < MAX_IN_FLIGHT && now >= nextLaunch) { const { operation, prompt } = queue[0]; nextLaunch = now + SUBMIT_PAUSE; let response = null; try { response = await fetch(`${API}/images/generate`, { method: "POST", headers: { ...AUTH, "Content-Type": "application/json", "X-Idempotency-Key": operation }, body: JSON.stringify({ model: "nano-banana-2.1", prompt, resolution: "1K", aspect_ratio: "1:1", }), signal: AbortSignal.timeout(30_000), }); } catch (error) { // 没有响应,但请求可能已经送达:下次用同一个幂等键再发 if (!noAnswer(error)) throw error; } if (response?.status === 202) { running.set((await response.json()).id, { operation, polledAt: now }); queue.shift(); } else if (response?.status === 429) { nextLaunch = now + Math.max(SUBMIT_PAUSE, retryAfter(response) * 1000); } else if (response && response.status < 500) { // 400、401、402、403、404:先排除原因 throw new Error(`HTTP ${response.status}: ${await response.text()}`); } else { const count = (failures.get(operation) ?? 0) + 1; failures.set(operation, count); if (count >= MAX_ATTEMPTS) throw new Error(`${operation}: 多次没有得到结果,请先查看请求记录`); } } for (const [id, state] of [...running]) { if (now - state.polledAt < POLL_PAUSE) continue; state.polledAt = now; let response; try { response = await fetch(`${API}/creations/${id}`, { headers: AUTH, signal: AbortSignal.timeout(20_000), }); } catch (error) { if (!noAnswer(error)) throw error; continue; } if (response.status === 429 || response.status >= 500) continue; if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`); const creation = await response.json(); if (creation.status === "completed" || creation.status === "failed") { finished.set(state.operation, creation); running.delete(id); } } await sleep(200); } const failed = [...finished].filter(([, c]) => c.status === "failed").map(([name]) => name); console.log(finished.size - failed.length, "个已完成;失败的:", failed);
示例里的数字是按余量选的,不是服务的建议。请把队列和操作表存在磁盘或数据库里,重启后才能用同样的幂等键继续。更多关于 429 的内容,见这篇讲 429 错误与限额的文章。
如何用 Webhook 接收结果, 而不是反复轮询?
在生成请求里传入 webhook_url,任务变为 completed 或 failed 时,我们会向这个地址发送带签名的 POST 请求,你不必每 5 秒查询一次。地址需要是公开的 HTTPS 地址,最多 2,048 个字符;无效或被禁止的地址会在扣费前返回 400。签名密钥整个账号共用一个,以 whsec_ 开头,在控制台的 Webhook 页面复制。
curl --fail-with-body --max-time 30 \
-X POST https://api.rendergrid.io/api/public/v1/images/generate \
-H "Authorization: Bearer $RENDERGRID_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Idempotency-Key: batch-7-0001" \
-d '{
"model": "nano-banana-2.1",
"prompt": "白色软管立在桃色台面上,左侧柔光",
"resolution": "1K",
"aspect_ratio": "1:1",
"webhook_url": "https://example.com/webhooks/rendergrid"
}'
事件体是 JSON,包含 event、id、status、result_urls 和 cost,失败事件还有 error 和 failure。
{
"event": "creation.completed",
"id": "5b0214ae-9e39-460a-820a-f6ae3e24400b",
"status": "completed",
"result_urls": [
"https:// …"
],
"cost": 0.02
}
{
"event": "creation.failed",
"id": "5b0214ae-9e39-460a-820a-f6ae3e24400b",
"status": "failed",
"result_urls": [],
"cost": 0.02,
"error": "Generation failed.",
"failure": {
"type": "error",
"code": "internal",
"retryable": true
}
}
如何验证签名
签名用来确认事件来自我们,并且没有被改动:取请求体的原始字节(解析 JSON 之前的字节),依次拼接 X-Timestamp 的值、一个点和请求体,用完整的签名密钥(包括 whsec_)计算 HMAC-SHA256,再把 sha256= 加上结果,与请求头 X-Webhook-Signature-256 做常量时间对比。时间戳不在时间窗口内就拒绝:文档示例用的是 300 秒,这是接收方自己的规则。
import hashlib import hmac import json import os import re import time from http.server import BaseHTTPRequestHandler, HTTPServer SECRET = os.environ["RENDERGRID_WEBHOOK_SECRET"] # 控制台里的签名密钥,完整保存,包括 whsec_ TOLERANCE_SECONDS = 300 # 时间窗口由接收方自己决定 def signature_ok(timestamp, raw_body, signature): if not re.fullmatch(r"[0-9]{1,12}", timestamp or ""): return False if not re.fullmatch(r"sha256=[0-9a-f]{64}", signature or ""): return False if abs(time.time() - int(timestamp)) > TOLERANCE_SECONDS: return False expected = "sha256=" + hmac.new( SECRET.encode("utf-8"), timestamp.encode("ascii") + b"." + raw_body, hashlib.sha256, ).hexdigest() return hmac.compare_digest(expected, signature) class Hook(BaseHTTPRequestHandler): def do_POST(self): raw_body = self.rfile.read(int(self.headers.get("Content-Length", "0"))) if not signature_ok( self.headers.get("X-Timestamp"), raw_body, self.headers.get("X-Webhook-Signature-256"), ): self.send_response(400) self.end_headers() return event = json.loads(raw_body) # 先保存,再回复;重复的投递按 (id, event) 去重 with open("events.jsonl", "a", encoding="utf-8") as out: out.write(json.dumps(event, ensure_ascii=False) + "\n") self.send_response(200) self.end_headers() HTTPServer(("", 8080), Hook).serve_forever()
// Node.js 22+,文件扩展名为 .mjs import { createHmac, timingSafeEqual } from "node:crypto"; import { appendFileSync } from "node:fs"; import { createServer } from "node:http"; const SECRET = process.env.RENDERGRID_WEBHOOK_SECRET; // 控制台里的签名密钥,完整保存,包括 whsec_ const TOLERANCE_SECONDS = 300; // 时间窗口由接收方自己决定 function signatureOk(timestamp, rawBody, signature) { if (typeof timestamp !== "string" || !/^[0-9]{1,12}$/.test(timestamp)) return false; if (typeof signature !== "string" || !/^sha256=[0-9a-f]{64}$/.test(signature)) return false; if (Math.abs(Date.now() / 1000 - Number(timestamp)) > TOLERANCE_SECONDS) return false; const expected = "sha256=" + createHmac("sha256", Buffer.from(SECRET, "utf8")) .update(timestamp + ".", "ascii") .update(rawBody) .digest("hex"); return timingSafeEqual(Buffer.from(expected, "ascii"), Buffer.from(signature, "ascii")); } createServer((req, res) => { const chunks = []; req.on("data", (chunk) => chunks.push(chunk)); req.on("end", () => { const rawBody = Buffer.concat(chunks); if ( !signatureOk(req.headers["x-timestamp"], rawBody, req.headers["x-webhook-signature-256"]) ) { res.writeHead(400).end(); return; } const event = JSON.parse(rawBody.toString("utf8")); // 先保存,再回复;重复的投递按 (id, event) 去重 appendFileSync("events.jsonl", JSON.stringify(event) + "\n"); res.writeHead(200).end(); }); }).listen(8080);
批量发送之前,可以在控制台向你的地址发送一条带签名的测试事件:id 是 test,带有 test: true,没有 status、result_urls 和 cost,只发一次,不会重试。请验证签名,返回 2xx,不要把它当作图片处理。
Webhook 没有送达时
任何 2xx 响应都表示“已收到”,其他响应和网络错误都视为失败,并重新投递:默认最多尝试五次,第一次在任务完成后立即进行,之后依次在上一次之后 60、120、240 和 480 秒。我们最多等待 10 秒的响应,所以请先保存事件或放进队列,再返回 2xx,下载图片放到之后。
同一次投递的重试里,X-Webhook-Delivery-ID 保持不变,可以帮助去重;对每一对 (id, event) 仍然只执行一次操作。投递失败不会让任务变为 failed,我们也不能保证每次都送达,所以请把轮询留作备用。
如何重试请求, 又不重复扣费?
连接可能在请求已到达我们、但你还没有收到响应时中断:这时没有幂等键就再发一次,等于多买一张图片。所以每个生成请求都要带上请求头 X-Idempotency-Key,没有它就没有防止重复执行的保护。
- 幂等键是非空字符串,长度不超过 128 个字符,否则返回
400 ERR_INVALID_REQUEST;可以用 UUID,或你系统里的操作编号。 - 幂等键只在同一个 API 密钥的范围内有效:换一个 API 密钥,即使属于同一账号,也会被视为新的操作。
- 幂等键不会比对请求体:用原来的幂等键发送不同的提示词,返回的仍是原来的响应。
# 一个操作一个幂等键;同一个请求发送了两次,例如连接中断之后 for attempt in 1 2; do curl --fail-with-body --max-time 30 \ -X POST https://api.rendergrid.io/ api/ public/ v1/ images/ generate \ -H "Authorization: Bearer $RENDERGRID_API_KEY" \ -H "Content-Type: application/json" \ -H "X-Idempotency-Key: batch-7-0001" \ -d '{ "model": "nano-banana-2.1", "prompt": "白色软管立在桃色台面上,左侧柔光", "resolution": "1K" }' echo done
import os import random import time import requests URL = "https://api.rendergrid.io/ api/ public/ v1/ images/ generate" HEADERS = {"Authorization": f"Bearer {os.environ['RENDERGRID_API_KEY']}"} def submit(payload, operation, attempts=3): for attempt in range(attempts): delay = 2 ** (attempt + 1) + random.random() try: r = requests.post( URL, headers={**HEADERS, "X-Idempotency-Key": operation}, json=payload, timeout=(5, 30), ) except (requests.Timeout, requests.ConnectionError): r = None # 没有响应,但请求可能已经送达:用同一个幂等键重试 if r is not None: if r.status_code == 202: return r.json() if r.status_code != 429 and r.status_code < 500: raise RuntimeError(f"HTTP {r.status_code}: {r.text}") # 先排除原因 wait = r.headers.get("Retry-After", "") if wait.isascii() and wait.isdigit(): delay = max(delay, int(wait)) if attempt + 1 < attempts: time.sleep(delay) raise RuntimeError("请求没有被接收:请先查看请求记录,不要直接换新的幂等键") creation = submit( { "model": "nano-banana-2.1", "prompt": "白色软管立在桃色台面上,左侧柔光", "resolution": "1K", }, operation="batch-7-0001", ) print(creation["id"])
// Node.js 22+,文件扩展名为 .mjs const ENDPOINT = "https://api.rendergrid.io/ api/ public/ v1/ images/ generate"; const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); async function submit(payload, operation, attempts = 3) { for (let attempt = 0; attempt < attempts; attempt++) { let delay = (2 ** (attempt + 1) + Math.random()) * 1000; let response = null; try { response = await fetch(ENDPOINT, { method: "POST", headers: { Authorization: `Bearer ${process.env.RENDERGRID_API_KEY}`, "Content-Type": "application/json", "X-Idempotency-Key": operation, }, body: JSON.stringify(payload), signal: AbortSignal.timeout(30_000), }); } catch (error) { // 没有响应,但请求可能已经送达:用同一个幂等键重试 if (!(error instanceof TypeError) && error.name !== "TimeoutError") throw error; } if (response) { if (response.status === 202) return response.json(); if (response.status !== 429 && response.status < 500) { throw new Error(`HTTP ${response.status}: ${await response.text()}`); // 先排除原因 } const wait = response.headers.get("Retry-After"); if (wait && /^[0-9]+$/.test(wait)) delay = Math.max(delay, Number(wait) * 1000); } if (attempt + 1 < attempts) await sleep(delay); } throw new Error("请求没有被接收:请先查看请求记录,不要直接换新的幂等键"); } const creation = await submit( { model: "nano-banana-2.1", prompt: "白色软管立在桃色台面上,左侧柔光", resolution: "1K", }, "batch-7-0001", ); console.log(creation.id);
对已被接收的请求,用同一个幂等键重试会返回相同的 202 响应:id、status、task_id 和 cost 都相同,没有新的图片,也没有新的扣费。这是为那次提交保存的响应,不是当前状态:图片已经就绪时,其中仍可能是 queued,最新状态请从 GET /creations/{id} 获取。
{
"id": "5b0214ae-9e39-460a-820a-f6ae3e24400b",
"status": "queued",
"task_id": "5b0214ae-9e39-460a-820a-f6ae3e24400b",
"cost": 0.02
}
{
"id": "5b0214ae-9e39-460a-820a-f6ae3e24400b",
"status": "queued",
"task_id": "5b0214ae-9e39-460a-820a-f6ae3e24400b",
"cost": 0.02
}
没有得到响应或收到 5xx 时,请用同一个幂等键重试同一个请求。429 且 details.reason 为 idempotency_in_flight,说明第一个请求还在接收中,等待 Retry-After 之后再重试。400、402 或 404 表示请求没有被接收,消除原因后用同一个幂等键重试。
如果任务已经从 202 变成了 failed,原来的幂等键不会重新启动它。再试一次需要新的幂等键:这是一次新的付费操作,而之前那笔费用会自动退回。
保存的响应有效期为 30 天;之后记录可能被删除,同一个幂等键就会启动一次新的付费生成。幂等键也不能在服务故障时提供无条件的保证:请限制尝试次数,并自己做好记录。仍不能确定请求是否已被接收时,请先查看控制台里的请求记录,或联系技术支持。
如何把这些做法 串起来?
要知道每个操作的结局,请为每个操作记一行:操作编号、幂等键、任务 id 和结果。批量任务这样循环:
- 从队列取出一个操作,带着它的幂等键发送请求;收到
202就记下任务id。 - 在 Webhook 接收端先验证签名,再保存,返回
2xx,最后才处理。 - 任务变为
completed后立即下载图片:结果文件只保存一天。 - 失败的任务如果要再试,请用新的幂等键发送新的请求:这是一次新的付费操作。
一批图片 的费用怎么算?
金额在请求被接收时、开始处理之前扣除;请求失败时,金额会立即退回余额。一批图片的费用,就是其中每个请求的价格之和:Nano Banana 2.1 的一张图片在 1K 下是 $0.02,在 2K 下是 $0.03,在 4K 下是 $0.04。
为了避免循环里的错误把余额用光,请为这批任务单独创建一个 API 密钥,并设置月度限额。这是硬性限制:用尽之后,生成请求会得到 402 ERR_INSUFFICIENT_BALANCE,也不会扣费。
关于失败请求的退款,见这篇讲失败请求的文章;价格见价格页。
哪些情况 不适合这样批量生成?
- 没有批量接口。队列、记录和重试都要你自己来写。
- Webhook 不保证每次都送达。事件可能延迟,也可能没有送达,所以要保留轮询作为备用。
- 三张示例图说明不了速度和可靠性。它们只是一次尝试的示例,不是测量。
常见问题解答
可以用一个请求生成多张图片吗?
n,API 会在扣费前返回 400。需要更多图片,就发送多个请求,每个请求用不同的幂等键。每分钟可以发送多少个请求?
用同一个幂等键发送两次请求会怎样?
202 响应,id 也相同:没有新的图片,也没有新的扣费。一批图片要等多久?
我们没有承诺的时限:它取决于模型和负载。请保存任务 id,等待超时的话,稍后继续查询。
来源
- Rendergrid 文档:限额请求速率、并行任务、轮询间隔和月度限额。
- Rendergrid 文档:Webhook事件、签名验证和重新投递。
- Rendergrid 文档:重试不重复扣费
X-Idempotency-Key的规则。 - Rendergrid 文档:任务与状态状态、任务响应和结果文件的保存期限。
- Rendergrid 价格页每张图片的价格。
- Rendergrid 统计模型近 7 天的平均等待时间。





