> ## Documentation Index
> Fetch the complete documentation index at: https://docs.narada.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Polling

> Poll for automation task completion and retrieve results

## Overview

Polling provides a pull-based mechanism for retrieving automation task results. After submitting a task via the [Remote Dispatch API](/api-reference/remote-dispatch), you can periodically check for completion using the [Get Task Status](/api-reference/get-task-status) endpoint.

<CardGroup cols={2}>
  <Card title="Simple Setup" icon="wrench">
    No webhook endpoints or server infrastructure required to get started
  </Card>

  <Card title="Firewall Friendly" icon="shield">
    Works in restricted network environments without opening inbound ports
  </Card>

  <Card title="No Server Required" icon="server">
    Perfect for scripts, CLI tools, and applications without a web server
  </Card>

  <Card title="Full Control" icon="sliders">
    You decide when and how often to check for results
  </Card>
</CardGroup>

## How Polling Works

When you submit an automation task, you receive a `requestId` that you can use to poll for the task status until it completes.

<Steps>
  <Step title="Submit Task">
    Send a request to the Remote Dispatch API and receive a `requestId`
  </Step>

  <Step title="Wait">
    Wait for an appropriate interval before checking status
  </Step>

  <Step title="Check Status">
    Call the Get Task Status endpoint with your `requestId`
  </Step>

  <Step title="Handle Response">
    If status is `pending`, go back to step 2. Otherwise, process the result.
  </Step>
</Steps>

<Info>
  Polling is ideal for simple integrations, scripts, and environments where setting up webhook endpoints isn't feasible.
</Info>

## Basic Implementation

Here's how to implement basic polling in different languages:

<CodeGroup>
  ```bash cURL theme={null}
  # Submit the task
  REQUEST_ID=$(curl -s -X POST 'https://api.narada.ai/fast/v2/remote-dispatch' \
    -H 'Content-Type: application/json' \
    -H 'x-api-key: YOUR_API_KEY' \
    -d '{
      "prompt": "/Operator search for software engineering jobs",
      "browserWindowId": "your-browser-window-id"
    }' | jq -r '.requestId')

  echo "Task submitted: $REQUEST_ID"

  # Poll for completion
  while true; do
    RESPONSE=$(curl -s -X GET "https://api.narada.ai/fast/v2/remote-dispatch/responses/$REQUEST_ID" \
      -H 'x-api-key: YOUR_API_KEY')

    STATUS=$(echo $RESPONSE | jq -r '.status')

    if [ "$STATUS" != "pending" ]; then
      echo "Task completed with status: $STATUS"
      echo $RESPONSE | jq '.response'
      break
    fi

    echo "Task still pending, waiting 5 seconds..."
    sleep 5
  done
  ```

  ```javascript Node.js theme={null}
  async function submitAndPoll(prompt, browserWindowId) {
    // Submit the task
    const submitResponse = await fetch(
      "https://api.narada.ai/fast/v2/remote-dispatch",
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "x-api-key": process.env.NARADA_API_KEY,
        },
        body: JSON.stringify({
          prompt,
          browserWindowId,
        }),
      }
    );

    const { requestId } = await submitResponse.json();
    console.log(`Task submitted: ${requestId}`);

    // Poll for completion
    while (true) {
      const statusResponse = await fetch(
        `https://api.narada.ai/fast/v2/remote-dispatch/responses/${requestId}`,
        {
          headers: {
            "x-api-key": process.env.NARADA_API_KEY,
          },
        }
      );

      const result = await statusResponse.json();

      if (result.status !== "pending") {
        console.log(`Task completed with status: ${result.status}`);
        return result;
      }

      console.log("Task still pending, waiting 5 seconds...");
      await new Promise((resolve) => setTimeout(resolve, 5000));
    }
  }

  // Usage
  const result = await submitAndPoll(
    "/Operator search for software engineering jobs",
    "your-browser-window-id"
  );
  console.log(result.response?.text);
  ```

  ```python Python theme={null}
  import requests
  import time
  import os

  def submit_and_poll(prompt: str, browser_window_id: str) -> dict:
      api_key = os.getenv('NARADA_API_KEY')

      # Submit the task
      submit_response = requests.post(
          'https://api.narada.ai/fast/v2/remote-dispatch',
          headers={
              'Content-Type': 'application/json',
              'x-api-key': api_key
          },
          json={
              'prompt': prompt,
              'browserWindowId': browser_window_id
          }
      )

      request_id = submit_response.json()['requestId']
      print(f"Task submitted: {request_id}")

      # Poll for completion
      while True:
          status_response = requests.get(
              f'https://api.narada.ai/fast/v2/remote-dispatch/responses/{request_id}',
              headers={'x-api-key': api_key}
          )

          result = status_response.json()

          if result['status'] != 'pending':
              print(f"Task completed with status: {result['status']}")
              return result

          print("Task still pending, waiting 5 seconds...")
          time.sleep(5)

  # Usage
  result = submit_and_poll(
      '/Operator search for software engineering jobs',
      'your-browser-window-id'
  )
  print(result.get('response', {}).get('text'))
  ```
</CodeGroup>

## Polling with Timeout

Here's a complete example with timeout handling:

```python theme={null}
import requests
import time
import os

def poll_for_result(request_id: str, timeout: int = 300, poll_interval: int = 5) -> dict:
    """Poll for task completion with timeout."""
    api_key = os.environ['NARADA_API_KEY']
    deadline = time.time() + timeout

    while True:
        remaining = deadline - time.time()
        if remaining <= 0:
            raise TimeoutError(f"Task did not complete within {timeout}s")

        # Check status
        response = requests.get(
            f'https://api.narada.ai/fast/v2/remote-dispatch/responses/{request_id}',
            headers={'x-api-key': api_key}
        )
        result = response.json()

        if result['status'] != 'pending':
            return result

        time.sleep(min(poll_interval, remaining))

# Usage
try:
    result = poll_for_result('req_abc123def456', timeout=120)

    if result['status'] == 'success':
        print(f"Success: {result['response']['text']}")
    elif result['status'] == 'error':
        print(f"Error: {result['response']['text']}")
    elif result['status'] == 'input-required':
        print(f"Input required: {result['response']['text']}")

except TimeoutError as e:
    print(f"Timeout: {e}")
```

## Response Handling

The Get Task Status endpoint returns different statuses that you should handle appropriately:

<Tabs>
  <Tab title="Pending">
    ```json theme={null}
    {
      "status": "pending",
      "response": null,
      "createdAt": "2024-12-19T00:00:00.000000+00:00",
      "completedAt": null
    }
    ```

    The task is still running. Continue polling after waiting.
  </Tab>

  <Tab title="Success">
    ```json theme={null}
    {
      "status": "success",
      "response": {
        "text": "Found 1,234 software engineering job listings.",
        "structuredOutput": {
          "count": 1234,
          "query": "software engineering jobs"
        }
      },
      "createdAt": "2024-12-19T00:00:00.000000+00:00",
      "completedAt": "2024-12-19T00:00:45.000000+00:00"
    }
    ```

    The task completed successfully. Process the response data.
  </Tab>

  <Tab title="Error">
    ```json theme={null}
    {
      "status": "error",
      "response": {
        "text": "Failed to complete the task due to network timeout."
      },
      "createdAt": "2024-12-19T00:00:00.000000+00:00",
      "completedAt": "2024-12-19T00:02:30.000000+00:00"
    }
    ```

    The task failed. Log the error and implement retry logic if appropriate.
  </Tab>

  <Tab title="Input Required">
    ```json theme={null}
    {
      "status": "input-required",
      "response": {
        "text": "The task requires authentication. Please log in to continue."
      },
      "createdAt": "2024-12-19T00:00:00.000000+00:00",
      "completedAt": null
    }
    ```

    The task needs user input. Notify the user or handle programmatically.
  </Tab>
</Tabs>

## Best Practices

<CardGroup cols={2}>
  <Card title="Use Reasonable Intervals" icon="clock">
    Poll every 5-10 seconds to balance responsiveness with API efficiency
  </Card>

  <Card title="Set Timeouts" icon="hourglass">
    Always implement maximum timeouts to prevent infinite polling loops
  </Card>

  <Card title="Handle All Statuses" icon="list-check">
    Implement handlers for success, error, input-required, and timeout scenarios
  </Card>

  <Card title="Log Progress" icon="file-lines">
    Log polling attempts for debugging and monitoring purposes
  </Card>

  <Card title="Handle Network Errors" icon="shield">
    Wrap API calls in try-except to handle transient network failures gracefully
  </Card>

  <Card title="Consider Webhooks" icon="bell">
    For production apps with many concurrent tasks, webhooks may be more efficient
  </Card>
</CardGroup>

## Comparison: Polling vs Webhooks

| Feature               | Polling                  | Webhooks            |
| --------------------- | ------------------------ | ------------------- |
| **Setup Complexity**  | Low                      | Medium              |
| **Infrastructure**    | None required            | Web server needed   |
| **Real-time Updates** | No (delayed by interval) | Yes                 |
| **Resource Usage**    | Higher (active requests) | Lower               |
| **Firewall Friendly** | Yes                      | Requires open ports |
| **Scalability**       | Limited                  | Excellent           |
| **Best For**          | Scripts, simple apps     | Production systems  |

<Tip>
  Start with polling for development and simple use cases. Migrate to [webhooks](/documentation/webhooks) when you need real-time notifications or are handling high volumes of tasks.
</Tip>

## Common Issues

<AccordionGroup>
  <Accordion title="Polling Too Frequently">
    **Problem**: Making too many requests and hitting rate limits.

    **Solution**: Use a reasonable polling interval of 5-10 seconds. This balances responsiveness with API efficiency.

    ```python theme={null}
    POLL_INTERVAL = 5  # seconds - good balance for most use cases
    time.sleep(POLL_INTERVAL)
    ```
  </Accordion>

  <Accordion title="No Timeout Implemented">
    **Problem**: Script runs forever if a task never completes.

    **Solution**: Always set a maximum timeout for your polling loop.

    ```python theme={null}
    start = time.time()
    while time.time() - start < MAX_TIMEOUT:
        # poll...
    raise TimeoutError("Task did not complete in time")
    ```
  </Accordion>

  <Accordion title="Not Handling All Status Types">
    **Problem**: Code breaks when receiving unexpected status values.

    **Solution**: Handle all possible statuses: `pending`, `success`, `error`, and `input-required`.

    ```python theme={null}
    if result['status'] == 'success':
        handle_success(result)
    elif result['status'] == 'error':
        handle_error(result)
    elif result['status'] == 'input-required':
        handle_input_required(result)
    ```
  </Accordion>

  <Accordion title="Missing Error Handling for API Calls">
    **Problem**: Network errors crash the polling loop.

    **Solution**: Wrap API calls in try-except and implement retry logic.

    ```python theme={null}
    try:
        response = requests.get(url, headers=headers, timeout=10)
        response.raise_for_status()
    except requests.RequestException as e:
        logger.warning(f"API request failed: {e}, retrying...")
        time.sleep(interval)
        continue
    ```
  </Accordion>
</AccordionGroup>
