---
title: Poll Until
description: Call an endpoint on an interval until a condition is met, or give up
---

Call a URL again and again until the response says it is ready, or give up after a deadline.

## What it does

On each poll, Poll Until sends the request you set up and checks the response against your **Done when** conditions (combined with AND / OR, as in [IF](/nodes/builtin/flow/if/)).

* When the conditions hold, the response leaves through **Done**.
* When the **Give up after** time passes first, the last response leaves through **Timeout**.

By default it polls **every 5 minutes** and gives up **after 1 hour**. Change the numbers and units to suit the job.

The conditions see the response as `{ status, ok, body }`:

* `status`: the HTTP status code, for example `200`.
* `ok`: `true` for a 2xx status.
* `body`: the JSON (or text) the endpoint returned.

So a condition's left side is a path such as `body.status`, `body.result.state` or `status`. A request that fails or times out counts as "not yet", and polling continues until the deadline.

How it waits between polls depends on the interval:

* **1 minute or more, in the browser extension**: durable. The run is saved between polls and resumes on time even if you close the tab or restart the browser. It shows as **waiting** in the Executions pane.
* **Under 1 minute, or in the web app**: a simple timer that stops if you close the tab.

## When to use it

* Start a long export, render or build with one request, then poll its status URL until it reports done.
* Wait for an outside system to reach a state: an order ships, a file appears, an approval flips.

## Inputs and settings

Put one header per line in **Headers**, as `Key: Value`, for example `Authorization: Bearer …`. **Body** is only sent for methods other than GET.

## Outputs

Both ports send the response as `{ status, ok, body }` (plus `error` when the last request failed). Read the result downstream with `{{ $input.body }}`.

## Dependencies and credentials

None. This node needs no connection and has no slots for other nodes.

Authentication goes in **Headers**.

## Example workflow

1. [Http Request](/nodes/builtin/core/http-request/) starts an export and returns a job id.
2. Poll Until calls `https://api.example.com/jobs/{{ $input.data.id }}` with **Done when** `body.status` (**String**) **Is Equal To** `finished`, **Poll every** 1 **Minutes**, **Give up after** 30 **Minutes**.
3. **Done** goes to an HTTP Request that downloads `{{ $input.body.downloadUrl }}`.
4. **Timeout** goes to a [Browser Notification](/nodes/extension/browsernotification/): "The export is stuck."

## Common issues

* **It always ends on Timeout.** Check the path on the left of the condition. It starts with `body.` for anything in the response content (`body.status`, not `status`, unless you mean the HTTP code).
* **It keeps polling after the job finished.** The value may differ from what you compare against, for example `Finished` versus `finished`, or a number compared as **String**.
* **A long poll stopped when you closed the tab.** Durable polling needs the extension and an interval of at least 1 minute.

## Related nodes

* [Wait](/nodes/builtin/flow/wait/): pause for a fixed time.
* [Loop](/nodes/builtin/flow/loop/): repeat any group of steps.
* [Http Request](/nodes/builtin/core/http-request/): a single call.
* [Wait For Approval](/nodes/builtin/flow/wait-for-approval/): wait for a person instead of a URL.