Skip to content

JavaScript, Python and n8n

These recipes use REST and your own secret. Save a UUID in INFINITY_FLOW_REQUEST_KEY before execution. Resume with the same UUID and payload after a lost response. Production credentials create real work.

Use Node with native fetch. Do not run this in browser code:

const base = 'https://infinityflow.stream/api/v1';
const key = process.env.INFINITY_FLOW_API_KEY;
const requestKey = process.env.INFINITY_FLOW_REQUEST_KEY;
if (!key || !requestKey) throw new Error('Configure a key and a persisted UUID.');
const headers = { Authorization: `Bearer ${key}`, 'Content-Type': 'application/json' };
const payload = { prompt: 'A forest at sunrise', mediaKind: 'video', aspect: '16:9' };
const response = await fetch(`${base}/generations`, {
method: 'POST',
headers: { ...headers, 'Idempotency-Key': requestKey },
body: JSON.stringify(payload),
signal: AbortSignal.timeout(30000),
});
const result = await response.json();
if (!response.ok) throw new Error(JSON.stringify(result));
const id = result.generation.id; // Persist the ID in your task.
console.log({ id, state: result.generation.state });
// Repeated GET is safe. Never retry POST with another key.
for (let attempt = 0; attempt < 120; attempt++) {
await new Promise(resolve => setTimeout(resolve, 5000));
const statusResponse = await fetch(`${base}/generations/${id}`, { headers });
const status = await statusResponse.json();
if (!statusResponse.ok) throw new Error(JSON.stringify(status));
if (status.generation.state === 'succeeded') {
const ticketResponse = await fetch(`${base}/generations/${id}/outputs/0/download-ticket`, { headers });
if (!ticketResponse.ok) throw new Error('Download is not available.');
const { url } = await ticketResponse.json();
// The following download uses NO Infinity Flow authentication headers.
const media = await fetch(url);
if (!media.ok) throw new Error('The link expired or the download failed.');
// Store media.body in your private storage. Never log the delivery URL.
break;
}
if (['failed', 'cancelled', 'attention_required'].includes(status.generation.state)) {
console.log({ id, state: status.generation.state });
break;
}
}

If polling ends without completion, keep the ID and retrieve it later. A local timeout neither cancels nor recreates the saved request. Production integrations should implement backoff and durable task storage.

import json, os, urllib.request
base = 'https://infinityflow.stream/api/v1'
key = os.environ['INFINITY_FLOW_API_KEY']
request_key = os.environ['INFINITY_FLOW_REQUEST_KEY'] # UUID saved before execution
payload = {'prompt': 'A forest at sunrise', 'mediaKind': 'video', 'aspect': '16:9'}
request = urllib.request.Request(
base + '/generations',
data=json.dumps(payload).encode(),
headers={'Authorization': 'Bearer ' + key,
'Content-Type': 'application/json',
'Idempotency-Key': request_key},
method='POST',
)
with urllib.request.urlopen(request, timeout=30) as response:
generation = json.load(response)['generation']
print({'id': generation['id'], 'state': generation['state']})
# Save generation['id']; retrieve GET /generations/{id} to track progress.
# After timeout, retain request_key/payload. Never automatically generate another UUID.
  1. Persist a UUID requestKey and payload at the task source. Do not regenerate the UUID on retry or substitute the workflow execution ID.
  2. Create an n8n Header Auth credential for Authorization: Bearer ...; do not embed the secret in exportable workflow fields.
  3. Configure HTTP Request as POST https://infinityflow.stream/api/v1/generations, JSON and Idempotency-Key: {{$json.requestKey}}. Map the persisted prompt, mediaKind and aspect.
  4. Save generation.id in the task before the next step.
  5. Use Wait and GET /generations/{id} for polling. Route succeeded to download; route attention_required, failed and cancelled to review without another automatic POST.
  6. Retrieve an authenticated download ticket, then download its URL in another HTTP Request without Header Auth credentials, storing binary output before expiry.

Before enabling creation-node retry, confirm the exact idempotency header and body are retained. Never route an error to a node that generates a different key for the same creation.