Bash for loop with curl: one API request per line
Loop over a file with while IFS= read -r, build each JSON body with jq --arg, send it with curl --fail-with-body, and pace it under the API's rate limit.

To send one curl request per item in bash, run curl inside a loop: for id in a b c; do curl ...; done for a short list, or while IFS= read -r line; do ...; done < file.txt for a file with one item per line. Build each JSON body with jq -n --arg instead of pasting text into quotes, and send it with curl --fail-with-body so a failed request shows up in your script.
The shell, jq and curl facts come from the Bash manual (Looping Constructs, Word Splitting, Builtins), the jq manual and the curl man page. The example API is Sume's, from Authentication, Video Generation and Errors and rate limits. All were read on 2026-09-29.
Why not loop with for line in $(cat file)?
A for loop runs its commands once for each word in the expanded list. An unquoted $(cat file) goes through word splitting, and when IFS is unset, space, tab and newline all split. A prompt like a red bike becomes three requests. A for loop is fine for ids without spaces; for lines, use while read:
IFS=for the read: whenIFSis null, no word splitting occurs, so the line stays whole.-r: backslash is not an escape character and stays part of the line.|| [ -n "$line" ]:readexits non-zero at end-of-file, which would drop a last line with no trailing newline.
How do I loop over a file of prompts with curl?
This script reads prompts.txt, starts one Sume video job per line, and saves each job id. Keep the key in SUME_API_KEY, never in the script; curl bearer token covers the Authorization header itself.
n=0
while IFS= read -r prompt || [ -n "$prompt" ]; do
n=$((n + 1))
body=$(jq -n --arg p "$prompt" \
'{model: "sume/auto", prompt: $p, aspect_ratio: "9:16", duration: 5}')
if resp=$(curl -sS --fail-with-body -X POST "https://api.sume.com/v1/videos" \
-H "Authorization: Bearer $SUME_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: batch-2026-09-29-line-$n" \
-d "$body"); then
echo "$resp" | jq -r '.id' >> jobs.txt
else
echo "line $n failed: $resp" >&2
fi
sleep 1
done < prompts.txtWhat does each flag do?
Each part of the script, as the jq and curl docs describe it:
jq -n --arg p "$prompt":-nbuilds JSON from scratch without reading input, and--argpasses the value in as a string, so quotes and backslashes in a prompt can't break the body. A broken body is a400 invalid_request; see 400 Bad Request invalid JSON.--fail-with-body: curl returns error 22 on an HTTP code of 400 or greater and still outputs the body, so you keep the error message. By default curl doesn't treat HTTP codes as failures. The option was added in curl 7.76.0.-sS: hides the progress meter but still shows errors.Idempotency-Key: one fixed key per line. If you rerun the script after a crash, the same line with the same body returns the original job on/v1/videosinstead of a second one. Reuse a key only for the same body: change the batch name when you edit the file or want new jobs.jq -r '.id': writes the string without JSON quotes.
How fast can a bash loop call the API?
As fast as the API's rate limit allows. Sume counts requests per key per minute, with writes (creates) and reads (status polls) in separate budgets. sleep 1 keeps the loop at about 60 creates a minute. For a faster loop, read the ratelimit-remaining header, and on a 429 wait for retry-after.
| Plan | Writes per minute | Reads per minute |
|---|---|---|
| Free | 120 | 4800 |
| Pro | 300 | 12000 |
| Startup | 600 | 24000 |
| Scale | 1200 | 48000 |
Should the loop wait for each job to finish?
No. Each create answers at once with a job id and a polling_url, and the video is generated asynchronously. Send the whole file first, then poll the saved ids in a second loop with GET /v1/videos/{id} until each status is no longer pending or in_progress. curl's --retry also exists, but it treats every 429 and 503 alike; a 429 queue_full means no new paid job until an existing one finishes or is canceled, so read the saved error body instead. For one scheduled call rather than a batch, see Crontab curl.
Sources
Related posts
More in Developers
- Batch video processing by API: one edit, many videos
Batch video processing by API is a loop: one edit job per file, each with its own idempotency key, collected by webhook. How it works on Sume, and costs.
- C# HttpClient default timeout: 100 seconds, and how to set it
HttpClient.Timeout defaults to 100 seconds per request and throws TaskCanceledException. How to set it, and why slow API jobs need polling instead.
- How to delete my data from an AI tool, and what stays
Delete your data from an AI tool in two steps: delete the account, then send a deletion request for stored files. How it works on Sume, and its limits.
- Do AI companies sell your data? What to read in the policy
Some may; the privacy policy is where to check. How to read its sale and sharing sections, and what Sume's policy says it collects and shares.
Written by Sume