#polling#async#one-off

“I kicked off an export/render that takes minutes and I need to poll until it's ready”

Poll an API until a long-running job finishes

Schedule a check, and have that check re-schedule itself until the upstream job is done. Fliq drives the polling loop on a timer so your process doesn't have to sit and wait.

You start a long job on a third-party API — a video render, a data export, a batch import — and it returns a task_id that you have to poll until it’s done. Holding a request open or running an in-process timer is fragile. Instead, let Fliq drive the loop: schedule a job that hits your own status-check endpoint, and have that endpoint schedule the next check if the work isn’t finished yet.

The request

Schedule the first check a little in the future. Your check endpoint does the upstream poll and decides whether to enqueue the next one.

# Kick off the first poll, 15s out
curl -X POST https://api.fliq.sh/jobs \
  -H "Authorization: Bearer fliq_sk_your_token" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/api/exports/check",
    "http_method": "POST",
    "scheduled_at": "2026-06-12T10:00:15Z",
    "headers": { "Content-Type": "application/json" },
    "body": "{\"task_id\":\"task_abc\"}",
    "max_retries": 3
  }'
// Your /api/exports/check handler:
export async function POST(req) {
  const { task_id } = await req.json();

  const status = await checkUpstream(task_id); // "running" | "done"
  if (status === "done") {
    await onExportReady(task_id);
    return Response.json({ done: true });
  }

  // Not ready — schedule the next poll 15s out.
  await fetch("https://api.fliq.sh/jobs", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.FLIQ_API_TOKEN}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      url: "https://yourapp.com/api/exports/check",
      http_method: "POST",
      scheduled_at: new Date(Date.now() + 15_000).toISOString(),
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ task_id }),
      max_retries: 3,
    }),
  });

  return Response.json({ done: false });
}

The loop ends when your handler sees done and simply doesn’t schedule another check.

What Fliq handles for you

  • The timer. Each poll is a real scheduled fire — no process needs to stay awake between checks, which suits serverless and Workers perfectly.
  • Retries on the check itself. If your status endpoint is briefly down when a poll fires, max_retries covers it; the loop doesn’t break on a transient blip.
  • History of every poll. Each check is a recorded execution, so a runaway loop or a stuck upstream is visible rather than mysterious.
  • A natural backoff. Widen the interval each time (15s, 30s, 60s) by computing scheduled_at from an attempt counter you carry in the body.
Drive polling loops on a timer — free during beta