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

# Scheduling & Webhooks

> Run agents automatically on a cron schedule or webhook trigger

Automate agent execution with **cron schedules** (run at fixed times) or **webhooks** (run when triggered by external systems). Schedules execute agents in the cloud — no infrastructure to manage.

## Quick Start

```bash theme={null}
# Create a daily cron schedule
orch schedule create acme/report-generator \
  --cron "0 9 * * *" \
  --timezone "America/New_York" \
  --input '{"format": "pdf"}'

# Create a webhook trigger
orch schedule create acme/github-processor --webhook

# List all schedules
orch schedule list

# Trigger a schedule manually (for testing)
orch schedule trigger <schedule-id>
```

***

## Cron Schedules

Cron schedules run agents at fixed intervals using standard cron expressions.

### Creating a Cron Schedule

```bash theme={null}
orch schedule create <org/agent[@version]> \
  --cron "<expression>" \
  [--timezone "<tz>"] \
  [--input '<json>'] \
  [--provider <provider>] \
  [--workspace <slug>]
```

| Flag                 | Description                                     | Default             |
| -------------------- | ----------------------------------------------- | ------------------- |
| `--cron <expr>`      | Cron expression (required for cron)             | —                   |
| `--timezone <tz>`    | IANA timezone                                   | `UTC`               |
| `--input <json>`     | Agent input as JSON string                      | `{}`                |
| `--provider <name>`  | LLM provider: `anthropic`, `openai`, `gemini`   | Agent default       |
| `--workspace <slug>` | Workspace slug                                  | Current workspace   |
| `--pin-version`      | Pin to this exact version (disable auto-update) | Auto-update enabled |

### Cron Expression Format

Standard five-field Unix cron syntax:

```
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-7, Sun = 0 or 7)
│ │ │ │ │
* * * * *
```

**Common examples:**

| Expression     | Runs                                |
| -------------- | ----------------------------------- |
| `0 9 * * *`    | Daily at 9:00 AM                    |
| `0 9 * * 1-5`  | Weekdays at 9:00 AM                 |
| `0 */6 * * *`  | Every 6 hours                       |
| `*/15 * * * *` | Every 15 minutes                    |
| `0 0 1 * *`    | First day of each month at midnight |
| `0 9 * * 1`    | Every Monday at 9:00 AM             |
| `30 2 * * 0`   | Every Sunday at 2:30 AM             |

### Timezone

Timezones use IANA identifiers. Some common values:

| Timezone          | Identifier            |
| ----------------- | --------------------- |
| US Eastern        | `America/New_York`    |
| US Pacific        | `America/Los_Angeles` |
| UK                | `Europe/London`       |
| Central Europe    | `Europe/Berlin`       |
| Japan             | `Asia/Tokyo`          |
| Australia Eastern | `Australia/Sydney`    |
| UTC (default)     | `UTC`                 |

### How Cron Execution Works

1. You create a schedule — orchagent registers a Cloud Scheduler job
2. At the scheduled time, the platform triggers the agent
3. Agent runs in a cloud sandbox with your stored LLM keys and workspace secrets
4. Run result is logged to your workspace run history
5. Next execution time is calculated and displayed

***

## Webhook Schedules

Webhook schedules let external systems trigger agent execution via HTTP POST.

### Creating a Webhook

```bash theme={null}
orch schedule create <org/agent[@version]> --webhook \
  [--input '<json>'] \
  [--provider <provider>] \
  [--workspace <slug>]
```

On creation, you'll receive a **webhook URL** containing a secret token:

```
https://api.orchagent.io/webhooks/{schedule_id}/{secret}
```

<Warning>
  The webhook secret is shown only once at creation time. Save it immediately.
</Warning>

### Calling a Webhook

External systems (GitHub Actions, Zapier, Stripe, etc.) send a POST request to the webhook URL:

```bash theme={null}
curl -X POST https://api.orchagent.io/webhooks/{schedule_id}/{secret} \
  -H "Content-Type: application/json" \
  -d '{"event": "new_issue", "repo": "acme/app"}'
```

The request body is merged with the schedule's default `input_data` and passed to the agent.

### Webhook Payload Format

**Request:**

Send a JSON object in the POST body. The webhook accepts any valid JSON:

```bash theme={null}
curl -X POST https://api.orchagent.io/webhooks/{schedule_id}/{secret} \
  -H "Content-Type: application/json" \
  -d '{"event": "new_issue", "repo": "acme/app", "number": 42}'
```

The platform merges the request body with the schedule's default `input_data` (request body takes precedence for overlapping keys). If no body is sent, the agent receives only the schedule's default input. Non-object JSON values (strings, arrays, numbers) are wrapped as `{"data": <value>}`.

**Response:**

```json theme={null}
{
  "run_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "success",
  "duration_ms": 3420,
  "output": { "result": "..." },
  "error": null
}
```

| Field          | Type      | Description                                          |
| -------------- | --------- | ---------------------------------------------------- |
| `run_id`       | `string`  | Unique run identifier                                |
| `status`       | `string`  | `success`, `error`, or `timeout`                     |
| `duration_ms`  | `integer` | Execution time in milliseconds                       |
| `output`       | `object`  | Agent output (null on error)                         |
| `error`        | `string`  | Error message (null on success)                      |
| `deduplicated` | `boolean` | `true` if an idempotency key matched an existing run |

### Webhook Security

The URL itself contains the secret token — no separate authentication headers needed. Treat the webhook URL like an API key:

* Don't commit it to source control
* Store it in your CI/CD secrets manager
* Regenerate by deleting and recreating the schedule if compromised

***

## Managing Schedules

### List Schedules

```bash theme={null}
# List all schedules
orch schedule list

# Filter by agent
orch schedule list --agent report-generator

# Filter by type
orch schedule list --type cron

# JSON output (for scripting)
orch schedule list --json

# Return only specific fields (implies --json)
orch schedule list --fields agent_name,cron_expression,enabled

# Paginate
orch schedule list --limit 10 --offset 20
```

Output shows: ID, agent, type, cron expression, enabled status, last run time, last status, and total run count.

### Update a Schedule

```bash theme={null}
# Change cron expression
orch schedule update <schedule-id> --cron "0 10 * * 1"

# Change timezone
orch schedule update <schedule-id> --timezone "America/Los_Angeles"

# Update input data
orch schedule update <schedule-id> --input '{"threshold": 2000}'

# Disable (pause) a schedule
orch schedule update <schedule-id> --disable

# Re-enable a schedule
orch schedule update <schedule-id> --enable

# Change LLM provider
orch schedule update <schedule-id> --provider openai

# Pin to current version (stop auto-updating)
orch schedule update <schedule-id> --pin-version

# Switch to a specific version
orch schedule update <schedule-id> --agent-version v2

# Re-enable auto-update
orch schedule update <schedule-id> --auto-update
```

<Note>
  Updating cron or timezone automatically recalculates the next execution time and updates the Cloud Scheduler job. Using `--agent-version` automatically disables auto-update (pins the schedule to the specified version).
</Note>

### Delete a Schedule

```bash theme={null}
orch schedule delete <schedule-id>
```

This permanently removes the schedule and its Cloud Scheduler job. Run history is retained.

### Trigger Manually

Test a schedule by triggering it immediately:

```bash theme={null}
# Trigger with the schedule's default input
orch schedule trigger <schedule-id>

# Trigger with custom input (overrides default)
orch schedule trigger <schedule-id> --input '{"test": true}'
```

The trigger runs synchronously and returns the agent output, status, and duration.

### View Schedule Details

```bash theme={null}
orch schedule info <schedule-id>
```

Shows schedule configuration, recent runs, and event timeline. Use `--json` for machine-readable output.

### View Run History

```bash theme={null}
# List recent runs
orch schedule runs <schedule-id>

# Filter by status
orch schedule runs <schedule-id> --status failed

# Limit results
orch schedule runs <schedule-id> --limit 50

# Paginate and filter fields
orch schedule runs <schedule-id> --limit 10 --offset 20 --fields status,duration_ms
```

***

## Version Management

By default, schedules **auto-update** when you publish a new version of the agent. This means your cron jobs and webhooks always run the latest code without manual intervention.

### Auto-Update (Default)

When you run `orch publish`, all enabled schedules for that agent in the same workspace are automatically updated to the new version. You'll see this in the schedule events:

```bash theme={null}
orch schedule info <schedule-id>
# Events: "version_updated" — Agent updated from v3 to v4
```

### Pinning a Version

If you need a schedule to stay on a specific version (e.g., for stability or testing), pin it at creation time:

```bash theme={null}
orch schedule create acme/data-processor@v2 \
  --cron "0 * * * *" \
  --pin-version
```

Or pin an existing schedule:

```bash theme={null}
orch schedule update <schedule-id> --pin-version
```

### Switching Versions

You can switch a schedule to any available version of the same agent:

```bash theme={null}
# Switch to a specific version
orch schedule update <schedule-id> --agent-version v2

# Switch to the latest version
orch schedule update <schedule-id> --agent-version v5
```

Changing version via `--agent-version` automatically disables auto-update, since explicitly choosing a version implies you want to control which version runs. A `version_updated` event is logged in the schedule's event timeline.

To re-enable auto-update later:

```bash theme={null}
orch schedule update <schedule-id> --auto-update
```

<Tip>
  Pinned schedules show a `[pinned]` badge in `orch schedule list`. Use pinning when you want to test a new version on one schedule before rolling it out to all of them.
</Tip>

***

## Workspace Secrets

If your agent needs external API keys or credentials at runtime (e.g., a database connection string, a third-party API key), you must:

1. Add the secrets to your workspace in the [dashboard](https://orchagent.io/dashboard)
2. Declare them in your agent's `orchagent.json`:

```json theme={null}
{
  "name": "my-agent",
  "required_secrets": ["EXTERNAL_API_KEY", "DATABASE_URL"]
}
```

Secrets listed in `required_secrets` are injected as environment variables into the sandbox at runtime. **Secrets not listed will not be available**, even if they exist in your workspace.

<Warning>
  This is the most common cause of scheduled agent failures. If your agent uses `os.environ["SOME_KEY"]` and you haven't added it to `required_secrets`, the run will fail with a cryptic error. Always declare every secret your code needs.
</Warning>

For more details, see the [manifest reference](/building-agents/manifest-format) and [workspace secrets guide](/building-agents/building-orchestrators#workspace-secrets).

***

## LLM Credentials

Scheduled runs use LLM keys from your workspace secrets vault:

1. If the schedule has a `--provider` set, that provider's key is used
2. Otherwise, the agent's default provider is used
3. LLM keys must exist in the vault before creating the schedule (e.g., `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`)

<Tip>
  Store your LLM API keys in the workspace vault: `orch secrets set ANTHROPIC_API_KEY sk-ant-...` or add them in the [dashboard](https://orchagent.io/dashboard) under Settings → Secrets.
</Tip>

***

## Failure Handling

orchagent tracks consecutive schedule failures and can automatically disable schedules that fail repeatedly.

### Failure Streaks

Each schedule tracks its consecutive failure count. When a schedule fails, the counter increments. When it succeeds, the counter resets to zero.

If the failure count reaches the threshold (default: 10, configurable 1-100), the schedule is **automatically disabled** to prevent runaway failures.

```bash theme={null}
# Check failure status
orch schedule list
# Shows: Fails column with consecutive_failures / max_consecutive_failures
# Shows: AUTO-DISABLED badge for auto-disabled schedules

# View failure details
orch schedule info <schedule-id>
```

### Re-enabling a Disabled Schedule

When you re-enable an auto-disabled schedule, the failure counter resets to zero:

```bash theme={null}
orch schedule update <schedule-id> --enable
```

<Note>
  Fix the underlying issue before re-enabling. The schedule will auto-disable again if failures continue.
</Note>

### Alert Webhooks

Get notified when schedules fail repeatedly. Configure an alert webhook URL via the API:

```bash theme={null}
curl -X PATCH https://api.orchagent.io/workspaces/{workspace_id}/schedules/{schedule_id} \
  -H "Authorization: Bearer $ORCHAGENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"alert_webhook_url": "https://your-webhook.example.com/alerts", "alert_on_failure_count": 3}'
```

Alerts fire at two points:

1. **Warning** — when `consecutive_failures` reaches `alert_on_failure_count` (default: 3)
2. **Auto-disable** — when the schedule is automatically disabled

Alert payload:

```json theme={null}
{
  "event": "schedule.failure_streak",
  "schedule_id": "...",
  "workspace_id": "...",
  "agent_name": "...",
  "consecutive_failures": 3,
  "threshold": 10,
  "auto_disabled": false,
  "last_error": "timeout"
}
```

Test your alert webhook:

```bash theme={null}
curl -X POST https://api.orchagent.io/workspaces/{workspace_id}/schedules/{schedule_id}/test-alert \
  -H "Authorization: Bearer $ORCHAGENT_API_KEY"
```

### Webhook Idempotency

Webhook triggers support idempotency to prevent duplicate executions. Pass an `idempotency-key` header:

```bash theme={null}
curl -X POST https://api.orchagent.io/webhooks/{schedule_id}/{secret} \
  -H "Content-Type: application/json" \
  -H "idempotency-key: unique-event-id-123" \
  -d '{"event": "new_issue"}'
```

If the same idempotency key is sent within the deduplication window, the platform returns the existing run result instead of executing again. This makes webhook retries safe.

***

## Examples

### Daily Report

```bash theme={null}
orch schedule create acme/report-generator \
  --cron "0 9 * * 1-5" \
  --timezone "America/New_York" \
  --input '{"recipients": "team@acme.com", "format": "pdf"}'
```

### Hourly Monitoring

```bash theme={null}
orch schedule create acme/health-checker \
  --cron "0 * * * *" \
  --input '{"endpoints": ["https://api.acme.com/health"]}'
```

### GitHub Webhook Integration

```bash theme={null}
# 1. Create webhook schedule
orch schedule create acme/pr-reviewer --webhook

# 2. Copy the webhook URL from the output
# 3. Add it to your GitHub repo → Settings → Webhooks
# 4. Every PR event triggers your agent
```

### Weekly Cleanup

```bash theme={null}
orch schedule create acme/data-cleanup \
  --cron "0 3 * * 0" \
  --input '{"max_age_days": 30, "dry_run": false}'
```

### Test Before Automating

```bash theme={null}
# First, test the agent manually
orch run acme/report-generator --data '{"format": "pdf"}'

# Then create the schedule
orch schedule create acme/report-generator \
  --cron "0 9 * * 1-5" \
  --timezone "America/New_York" \
  --input '{"format": "pdf"}'

# Verify with a manual trigger
orch schedule trigger <schedule-id>
```

***

## Permissions

| Operation             | Required Role |
| --------------------- | ------------- |
| List schedules        | Member        |
| Create schedule       | Owner         |
| Update schedule       | Owner         |
| Delete schedule       | Owner         |
| Trigger schedule      | Owner         |
| View schedule details | Member        |
| View run history      | Member        |

***

## Limits

Scheduling is included on Pro, Team, and Enterprise plans. Schedule limits depend on your plan tier. Agent execution time counts toward your workspace compute usage.

***

## Troubleshooting

**Schedule not executing?**

* Check that the schedule is enabled: `orch schedule list`
* Verify your LLM keys are configured in the workspace
* Try a manual trigger to see the error: `orch schedule trigger <id>`

**Webhook not receiving?**

* Verify the URL is correct (the secret is part of the URL)
* Check the external system is sending `Content-Type: application/json`
* Webhook URLs are public — no firewall allowlisting needed

**Schedule auto-disabled?**

* The schedule hit its consecutive failure threshold and was automatically paused
* Check recent failures: `orch schedule info <id>`
* Fix the root cause, then re-enable: `orch schedule update <id> --enable`

**Agent fails with empty env vars or 500 error?**

* Your agent probably uses workspace secrets but doesn't declare them in `orchagent.json`
* Add `"required_secrets": ["SECRET_NAME"]` to your `orchagent.json` and republish
* See [Workspace Secrets](#workspace-secrets) above

**Wrong timezone?**

* Use IANA identifiers (e.g., `America/New_York`), not abbreviations like `EST`
* Update with: `orch schedule update <id> --timezone "America/New_York"`
