Getting results
Wait for a generation, read its status, and save the file before the link dies.
Read as MarkdownA submit answers when the job is accepted, not done. You wait on it, then fetch a short-lived link.
Wait for it
GET /generations/{id}/wait blocks up to 20 seconds. It answers the moment the job ends. Still going? It returns still_running: true. Call again right away.
const BASE = "https://app.riffads.com/api/v1";
const headers = { Authorization: `Bearer ${process.env.RIFFADS_API_KEY}` };
async function waitFor(generationId: string, maxAgeSeconds = 1800) {
for (;;) {
const res = await fetch(`${BASE}/generations/${generationId}/wait`, { headers });
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
if (!body.still_running) return body.generation;
if (body.age_seconds > maxAgeSeconds) {
throw new Error(`${generationId} still running after ${body.age_seconds}s`);
}
}
}- Branch on
still_running, notstatus. It can end beforestatuslooks final. - A timeout is a normal
200, never408or504. - Log
age_seconds. It tells stuck from slow.
Statuses
| Status | Means | Done? |
|---|---|---|
queued | Accepted, not started | No |
rendering | Working | No |
post_processing | Saving the output | No |
completed | Every output delivered | Yes |
failed | Did not deliver. Read error.code and error.message | Yes |
There is no canceled status. A canceled job reads failed. More: statuses and ids.
Variants
Sent variants: 3? The submit returns a batch_group_id (bg_). Watching one id is not enough. Wait on one sibling, then read GET /batches/{id}. Batch status is running, completed, failed or partial.
Signed links
Every output sits in generation.outputs[]:
| Field | Notes |
|---|---|
index | Stable position. Name files after it |
kind | image, video or audio |
url | Signed link, or null until the job is completed and settled |
width, height | Pixels, or null |
- Links live 600 seconds (
output_urls_expire_in_seconds). - There is no refresh endpoint. Every read signs new links. Expired? Read the generation again.
- A link is a credential. Anyone holding it gets the file. Don't store it, log it or queue it.
- Compare
outputs_deliveredtooutputs_expected, not the array length. - Text capabilities (AI Writer, Transcribe) return no file.
Download
BASE=https://app.riffads.com/api/v1
GEN=gen_0193c8f0a1b24e7f9d3c5a6b7e8f0033
curl -s "$BASE/generations/$GEN" -H "Authorization: Bearer $RIFFADS_API_KEY" \
| jq -r '.generation.outputs[] | select(.url != null) | [.index, .url] | @tsv' \
| while IFS=$'\t' read -r index url; do
curl -sS --fail -o "$GEN-$index" "$url"
doneA 403 on download usually means the link expired
Don't retry the same URL. Read the generation again for a fresh link, then fetch.
Fetch each link right after the read that signed it. Name saved files from generation_id, index and kind, not file_name. The download has no Content-Disposition, so browsers play it instead of saving it.
Webhooks
There are none. No webhook_url, no callback, no stream. Sending a callback field is a 400. Use the wait loop.
Keep your generation_id. There is no list endpoint, so it is your only way back to the file.