> An installable agent skill for AI Content Drop. Machine-readable copy: > https://aicontentdrop.com/skills/batch-generation-runner/SKILL.md. > Ships with the aicontentdrop package, and is listed in > /skills/index.json.
Running many generations without melting the rate limit
The failure mode this skill prevents: a loop that fires one HTTP request per item, hits the 120-per-minute ceiling a third of the way through, and leaves the user with a half-finished storyboard and no idea which shots exist.
Quote the whole job first, in one call
Never loop the cost endpoint. POST /v1/models/cost prices up to 50 model/quantity pairs together, needs no credential, and reports errors per item so one bad model id does not fail the quote:
curl -sX POST https://aicontentdrop.com/v1/models/cost \
-H "Content-Type: application/json" \
-d '{"items":[{"model_id":"kling_3_0","quantity":8},
{"model_id":"veo_3_fast","quantity":2}]}'
{
"count": 2,
"credits_total": 204,
"items": [
{ "index": 0, "model_id": "kling_3_0", "credits_each": 22, "quantity": 8,
"credits_total": 176, "type": "video", "error": null },
{ "index": 1, "model_id": "veo_3_fast", "credits_each": 14, "quantity": 2,
"credits_total": 28, "type": "video", "error": null }
]
}
Show the user credits_total before you start. A twenty-shot board on a premium model is a materially different decision from the same board on a cheap one, and they can only make that decision before the credits are gone.
Batch the reads
POST /v1/batch takes up to 20 read operations and returns results in the same order. No credential required.
curl -sX POST https://aicontentdrop.com/v1/batch \
-H "Content-Type: application/json" \
-d '{"operations":[
{"id":"video-models","method":"GET","path":"/v1/models?type=video"},
{"id":"image-models","method":"GET","path":"/v1/models?type=image"},
{"id":"quote","method":"GET","path":"/v1/models/kling_3_0/cost?quantity=3"}
]}'
The envelope is 200 even when an individual operation fails; each result carries its own status and error. So check per item, never just the outer status:
for (const r of body.results) {
if (r.status !== 200) console.warn(r.id, r.error?.code ?? r.status);
}
Rules worth knowing before you design around it:
- Reads only. Generation is never batched. A partial failure inside a batch
- 20 operations maximum. Over that, split the list.
- Same order in, same order out, and each result carries the
idyou gave.
of credit-spending calls is ambiguous in exactly the way that loses someone credits they cannot account for.
Generations: submit and poll, one key each
Generation is asynchronous. You get a 202 with an id, not a finished video.
curl -sX POST https://aicontentdrop.com/v1/generate/video \
-H "Authorization: Bearer $ACD_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: shot-04-take-1" \
-d '{"prompt":"…","model":"kling_3_0"}'
Then poll GET /v1/videos/{id} every 5 seconds until status leaves generating. Terminal states are completed, failed, and timeout.
Give every item its own Idempotency-Key derived from the item, not from the attempt — shot-04-take-1, not a fresh UUID per retry. That is what makes the whole run resumable: re-running the loop after a crash returns the existing generation for items already submitted (24-hour retention) instead of paying twice.
A run loop that survives contact with reality
const CONCURRENCY = 4; // stay well inside 120/min with polling
const inflight = new Map();
for (const shot of shots) {
while (inflight.size >= CONCURRENCY) await settleOne(inflight);
const res = await post("/v1/generate/video", shot.body, {
"Idempotency-Key": `${runId}:${shot.id}`,
});
if (res.status === 429) { // obey, do not spin
await sleep(Number(res.headers["retry-after"]) * 1000);
continue;
}
inflight.set(shot.id, res.body.id);
}
Two things that loop gets right and a naive one does not: it bounds concurrency so polling traffic still fits the budget, and it sleeps for exactly Retry-After on a 429 rather than retrying immediately, which extends the window rather than shortening it.
Report honestly at the end
Credits are charged only on success, so the arithmetic a user needs is:
- items completed × the model's flat cost = what they actually spent
- items failed or timed out = zero credits, nothing to reclaim
State both. A run that produced 17 of 20 clips cost 17 clips' worth, and the three failures are free to retry.
Full reference: <https://aicontentdrop.com/docs/batch>
---
Install the plugin: https://aicontentdrop.com/plugin · All skills: https://aicontentdrop.com/skills