# Schedule autonomous runs

You can schedule an agent to run a specific intervals using **Scheduled Runs.**

Each agent can have multiple schedules, allowing you to run it the same agent at multiple intervals or for each one of your users.

Each Scheduled Run creates an [Agent Run](https://docs.toolhouse.ai/toolhouse/agent-workers/running-agents-asynchronously), so you can expect Schedules to work similarly. In fact, the difference between Scheduled Runs and Agent Runs is that Agent Runs run once immediately, while Scheduled Runs run at a cadence. Just like Agent Runs, you can optionally specify a [bundle](https://docs.toolhouse.ai/toolhouse/advanced-concepts/bundles) to further tailor the functionality of your agent, as well as a [Toolhouse ID metadata.](https://docs.toolhouse.ai/toolhouse/advanced-concepts/using-metadata)

## Getting started with Scheduled Runs

Make sure you have your API Key ready. You can see or create an API key in the [API Keys page](https://app.toolhouse.ai/settings/api-keys).

### Specifying a cadence

{% hint style="info" %}
The minimum cadence for a Scheduled Run is every 10 minutes. If you specify a shorter cadence, your agent will still run at the minimum cadence.
{% endhint %}

You'll need to specify how often you want to agent to run. The minimum cadence is every 10 minutes. To specify a cadence, simply provide a cron expression or a plain text description of the cadence. Scheduled Runs has a dedicated endpoint to translate plain text to cron:

{% tabs %}
{% tab title="Python" %}

```python
import requests
import json

def send_request(toolhouse_api_key, cadence):
    params = { "cron": cadence }
    url = "https://api.toolhouse.ai/v1/schedules/text-to-cron"
    headers = {
        "Authorization": f"Bearer {toolhouse_api_key}",
    }

    response = requests.get(url, params=params, headers=headers, json=payload)

    return response

# Example usage
if __name__ == "__main__":
    toolhouse_api_key = "YOUR_TOOLHOUSE_API_KEY"
    cadence = "sundays at 5pm UTC"

    response = send_request(toolhouse_api_key, cadence)

    # Check if the request was successful
    if response.status_code == 200:
        print("Request successful. Response:")
        print(response.json())
    else:
        print("Request failed with status code", response.status_code)
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
async function createAgentRun(toolhouseApiKey, cadence) {
  try {
    const url = new URL('https://api.toolhouse.ai/v1/schedules/text-to-cron');
    url.searchParams.set('cron', cadence);
    const headers = {
      'Authorization': `Bearer ${toolhouseApiKey}`,
    };

    const response = await fetch(url, { headers });

    if (response.ok) {
      const data = await response.json();
      console.log(data);
    } else {
      console.error('Failed to retrieve data:', response.status, response.statusText);
    }
  } catch (error) {
    console.error('An error occurred:', error);
  }
}

// Example usage
const toolhouseApiKey = 'YOUR_TOOLHOUSE_API_KEY';
const cadence = 'sundays 5pm UTC';
await createAgentRun(toolhouseApiKey, cadence);
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl "https://api.toolhouse.ai/v1/schedules/text-to-cron?cron=sundays+5pm+UTC" \
-H "Authorization: Bearer $YOUR_TOOLHOUSE_API_KEY"
```

{% endtab %}
{% endtabs %}

This will return a cron expression you can use in subsequent requests.

```json
{
  "data": "0 17 * * 0"
}
```

### Creating a Scheduled Run

{% hint style="success" %}
**Agent tokens are free**

All Scheduled Runs use a premium LLM model. For a limited time, LLM tokens are free, meaning you will **not** need to worry about cost per token. Your account will only be charged for Toolhouse Execs.
{% endhint %}

1. Head over to Agent Studio and create a chat. If you're looking for inspiration, you can use [this prompt](https://chat.toolhouse.ai/?chat=1dd12fa3-cc9c-4786-96b8-d11aef274bdf).
2. Click the Share button, then copy the Chat ID.<br>

   <figure><img src="https://3896932452-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fio16js3ONksvIYTf7YUl%2Fuploads%2FgICZ3uFenQMCam11aZPc%2FCleanShot%202025-02-24%20at%2009.52.24.gif?alt=media&#x26;token=ffaf213f-5aa3-4772-a30a-780abc7ebac6" alt=""><figcaption></figcaption></figure>
3. Create an Scheduled Run using the Scheduled Runs API:

{% tabs %}
{% tab title="Python" %}

```python
import requests
import json

def send_request(toolhouse_api_key, chat_id):
    url = "https://api.toolhouse.ai/v1/schedules"
    headers = {
        "Authorization": f"Bearer {toolhouse_api_key}",
        "Content-Type": "application/json"
    }

    # Set the JSON payload
    payload = {
        "chat_id": chat_id,
        "cadence": "0 17 * * 0",
    }

    # Send the POST request
    response = requests.post(url, headers=headers, json=payload)

    return response

# Example usage
if __name__ == "__main__":
    toolhouse_api_key = "YOUR_TOOLHOUSE_API_KEY"
    chat_id = "YOUR_CHAT_ID"

    response = send_request(toolhouse_api_key, chat_id)

    # Check if the request was successful
    if response.status_code == 200:
        print("Request successful. Response:")
        print(response.json())
    else:
        print("Request failed with status code", response.status_code)
```

{% endtab %}

{% tab title="JavaScript" %}

<pre class="language-javascript"><code class="lang-javascript"><strong>async function createAgentRun(toolhouseApiKey, chatId) {
</strong>  try {
    const url = 'https://api.toolhouse.ai/v1/agent-runs';
    const headers = {
      'Authorization': `Bearer ${toolhouseApiKey}`,
      'Content-Type': 'application/json',
    };

    const body = JSON.stringify({
      'chat_id': chatId,
      'cadence': '0 17 * * 0',
    });

    const response = await fetch(url, {
      method: 'POST',
      headers: headers,
      body: body,
    });

    if (response.ok) {
      const data = await response.json();
      console.log(data);
    } else {
      console.error('Failed to retrieve data:', response.status, response.statusText);
    }
  } catch (error) {
    console.error('An error occurred:', error);
  }
}

// Example usage
const toolhouseApiKey = 'YOUR_TOOLHOUSE_API_KEY';
const chatId = 'your_chat_id';
await createAgentRun(toolhouseApiKey, chatId);
</code></pre>

{% endtab %}

{% tab title="cURL" %}

```sh
curl "https://api.toolhouse.ai/v1/agent-runs" \
-H "Authorization: Bearer $YOUR_TOOLHOUSE_API_KEY" \
--json '{
  "chat_id": "your_chat_id",
  "cadence": "0 17 * * 0"
}'
```

{% endtab %}
{% endtabs %}

Your Scheduled Run entry will be created.

```json
{
  "data": {
    "id": "bcb7e865-9e6c-xxxx-xxxx-c0110fdf5c2e",
    "created_at": "2025-01-15T01:46:23.568338",
    "updated_at": "2025-01-15T01:46:23.568338",
    "cadence": "0 17 * * 0",
    "active": true,
    "bundle": "default",
    "toolhouse_id": "default"
  }
}
```

### Changing the cadence of a Scheduled Run

You can change the cadence of a Scheduled Run at any time.

{% tabs %}
{% tab title="Python" %}

```python
import requests
import json

def send_request(toolhouse_api_key, schedule_id, cadence):
    url = f"https://api.toolhouse.ai/v1/schedules/{schedule_id}"
    headers = {
        "Authorization": f"Bearer {toolhouse_api_key}",
        "Content-Type": "application/json"
    }

    payload = {
        "cadence": cadence
    }

    response = requests.put(url, headers=headers, json=payload)

    return response

# Example usage
if __name__ == "__main__":
    toolhouse_api_key = "YOUR_TOOLHOUSE_API_KEY"
    schedule_id = "YOUR_SCHEDULE_ID"
    cadence = "0 */3 * * *"

    response = send_request(toolhouse_api_key, schedule_id, cadence)

    # Check if the request was successful
    if response.status_code == 200:
        print("Request successful. Response:")
        print(response.json())
    else:
        print("Request failed with status code", response.status_code)
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
async function updateScheduleCadence(toolhouseApiKey, scheduleId, cadence) {
  try {
    const url = `https://api.toolhouse.ai/v1/schedules/${scheduleId}`;
    const headers = {
      'Authorization': `Bearer ${toolhouseApiKey}`,
      'Content-Type': 'application/json',
    };

    const body = JSON.stringify({
      'cadence': cadence,
    });

    const response = await fetch(url, {
      method: 'PUT',
      headers: headers,
      body: body,
    });

    if (response.ok) {
      const data = await response.json();
      console.log(data);
    } else {
      console.error('Failed to update cadence:', response.status, response.statusText);
    }
  } catch (error) {
    console.error('An error occurred:', error);
  }
}

// Example usage
const toolhouseApiKey = 'YOUR_TOOLHOUSE_API_KEY';
const scheduleId = 'YOUR_SCHEDULE_ID';
const cadence = '0 */3 * * *';

await updateScheduleCadence(toolhouseApiKey, scheduleId, cadence);
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl -X PUT \
  "https://api.toolhouse.ai/v1/schedules/$YOUR_SCHEDULE_ID" \
  -H 'Authorization: Bearer $YOUR_TOOLHOUSE_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"cadence": "0 */3 * * *"}'
```

{% endtab %}
{% endtabs %}

### Pausing or resuming a Scheduled Run

When you pause a Scheduled Run, you interrupt its scheduled cadence without deleting it by setting its `active`field to `false`. This is useful to keep the configuration of your Scheduled Run without deleting it completely. You can resume its execution at any time by changing its `active`field back to `true`.

Any currently active Runs will pause at the end of their execution.

{% tabs %}
{% tab title="Python" %}

```python
import requests
import json

def send_request(toolhouse_api_key, schedule_id, is_active):
    url = f"https://api.toolhouse.ai/v1/agent-runs/{schedule_id}"
    headers = {
        "Authorization": f"Bearer {toolhouse_api_key}",
        "Content-Type": "application/json"
    }

    payload = {
        "active": is_active
    }

    response = requests.put(url, headers=headers, json=payload)

    return response

# Example usage
if __name__ == "__main__":
    toolhouse_api_key = "YOUR_TOOLHOUSE_API_KEY"
    schedule_id = "YOUR_SCHEDULE_ID"
    is_active = False

    response = send_request(toolhouse_api_key, schedule_id, is_active)

    # Check if the request was successful
    if response.status_code == 200:
        print("Request successful. Response:")
        print(response.json())
    else:
        print("Request failed with status code", response.status_code)
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
async function updateScheduleStatus(toolhouseApiKey, scheduleId, isActive) {
  try {
    const url = `https://api.toolhouse.ai/v1/agent-runs/${scheduleId}`;
    const headers = {
      'Authorization': `Bearer ${toolhouseApiKey}`,
      'Content-Type': 'application/json',
    };

    const payload = {
      'active': isActive,
    };

    const response = await fetch(url, {
      method: 'PUT',
      headers: headers,
      body: JSON.stringify(payload),
    });

    if (response.ok) {
      const data = await response.json();
      console.log(data);
    } else {
      console.error('Failed to retrieve data:', response.status, response.statusText);
    }
  } catch (error) {
    console.error('An error occurred:', error);
  }
}

// Example usage
const toolhouseApiKey = 'YOUR_TOOLHOUSE_API_KEY';
const scheduleId = 'YOUR_SCHEDULE_ID';
const isActive = false;

updateScheduleStatus(toolhouseApiKey, scheduleId, isActive);
```

{% endtab %}

{% tab title="cURL" %}

```sh
curl -XPUT \
  "https://api.toolhouse.ai/v1/schedules/$YOUR_SCHEDULE_ID" \
  -H 'Authorization: Bearer $YOUR_TOOLHOUSE_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"active": false}'
```

{% endtab %}
{% endtabs %}

### Deleting a Scheduled Run

Lastly, you can completely delete a Scheduled Run. Any currently active Runs will stop running at the end of their execution.

{% tabs %}
{% tab title="Python" %}

```python
import requests
import json

def send_request(toolhouse_api_key, schedule_id):
    url = f"https://api.toolhouse.ai/v1/agent-runs/{schedule_id}"
    headers = {
        "Authorization": f"Bearer {toolhouse_api_key}",
    }
    
    response = requests.delete(url, headers=headers)

    return response

# Example usage
if __name__ == "__main__":
    toolhouse_api_key = "YOUR_TOOLHOUSE_API_KEY"
    schedule_id = "YOUR_SCHEDULE_ID"

    response = send_request(toolhouse_api_key, schedule_id)

    # Check if the request was successful
    if response.status_code == 200:
        print("Request successful. Response:")
        print(response.json())
    else:
        print("Request failed with status code", response.status_code)
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
async function cancelScheduleRun(toolhouseApiKey, scheduleId) {
  try {
    const url = `https://api.toolhouse.ai/v1/agent-runs/${scheduleId}`;
    const headers = {
      'Authorization': `Bearer ${toolhouseApiKey}`,
    };

    const response = await fetch(url, {
      method: 'DELETE',
      headers: headers,
    });

    if (response.ok) {
      console.log('Request successful. Response:', await response.json());
    } else {
      console.error('Request failed with status code', response.status);
    }
  } catch (error) {
    console.error('An error occurred:', error);
  }
}

// Example usage
const toolhouseApiKey = 'YOUR_TOOLHOUSE_API_KEY';
const scheduleId = 'YOUR_SCHEDULE_ID';
await cancelScheduleRun(toolhouseApiKey, scheduleId);
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl -XDELETE \
  "https://api.toolhouse.ai/v1/schedules/$YOUR_SCHEDULE_ID" \
  -H 'Authorization: Bearer $YOUR_TOOLHOUSE_API_KEY'
```

{% endtab %}
{% endtabs %}
