> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.runtype.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.runtype.com/_mcp/server.

# Automating batch processing

Use a recurring Schedule to run a Flow or Agent against Records. Runtype resolves the Record target each time the Schedule runs, so a Record type target includes Records added after you create the Schedule.

## Use cases

Use a Schedule for the following workloads:

* Enrich Records that arrive during the day.
* Generate a weekly report from Records.
* Archive or update old Records.
* Refresh cached data from external sources.

## Before you begin

Create the Records to process, then create and test the Flow or Agent that processes them.

A Flow reads the Record it is processing through the `_record` variables, such as `{{_record.id}}`, `{{_record.name}}`, and `{{_record.metadata.company_name}}`. For the full list, see [Flow variables and templates](/user-guide/flows/flow-variables-and-templates).

For an Agent Schedule that uses Records, add messages to each Record. Runtype skips Records without messages. To run the same fixed conversations on every run instead of Record messages, set **Input Source** to **Message Sets**. Each Message Set runs as a separate Agent execution.

### Mark Records as processed

To process each Record once, add a step at the end of the Flow that marks the Record as processed. The Schedule's filter then excludes that Record on later runs.

Follow these steps to add the marker to a Flow:

1. In your Flow, add **Update Record** after the processing steps.
2. In **Find record**, select **From context**. The step updates the Record that the Schedule is processing.
3. In **Update metadata**, enter `processed` as the key, select **Boolean**, and turn the switch on so the value is `true`.

**Update Record** merges the update into the existing metadata, so other fields stay unchanged. Do not use **Upsert Record** for this step: it matches Records by type and name, and it can create a new Record instead of marking the current one. For more about these steps, see [Using records in flows](/user-guide/records/using-records-in-flows).

## Choose a Record target

A Schedule resolves its Record target each time it runs. Choose the target that matches your workload.

### Use a Record type

Use a Record type to process every Record of that type. Records added to the type enter the target on a later run.

### Use a Record Filter

Use a Record Filter to process only Records that match conditions on metadata fields. Runtype evaluates the filter each time the Schedule runs, so Records enter or leave scope as their metadata changes. For every operator, see [Filtering and searching records](/user-guide/records/filtering-and-searching-records).

Use the following filter to target customer Records that are not processed:

```json
{
  "type": "customers",
  "where": {
    "op": "and",
    "conditions": [{ "field": "processed", "op": "neq", "value": true }]
  }
}
```

This filter matches Records of type `customers` whose `processed` field is not `true`, including Records that do not have a `processed` field yet. Do not use `"op": "eq", "value": false` for this pattern: `eq` does not match Records where the field is missing, so new Records never enter the target. For details, see [Null and missing values](/user-guide/records/filtering-and-searching-records#null-and-missing-values).

In the dashboard, the filter conditions are chips. The preceding example is the chip `processed` **is not** `true`. Through the API, pass the filter as `target.recordFilter`.

### Use Record IDs

Use Record IDs to process a fixed set of Records. The target keeps the configured IDs, so later Records do not enter the target automatically. The dashboard does not offer this target. Through the API, pass the IDs in `target.recordIds`.

### Target limits

* Each run processes up to 50,000 Records from a Record type or Record Filter target. Records beyond that limit are not processed in that run. With a processed marker, later runs pick up the remaining Records.
* If an API request sets more than one target, the Schedule uses only one. `target.recordFilter` takes precedence over `target.recordIds`, and `target.recordIds` takes precedence over `target.recordType`.

## Set up batch processing

Follow these steps to create a recurring Schedule that processes Records:

1. Open **Schedules** from the sidebar.
2. Click **New schedule**.
3. Select **Flow** or **Agent**, then select the Flow or Agent to run.
4. Set **Input Source** to **Records**.
5. In **Records**, select a **Record type**. Add filter conditions to limit the Records. For the processed pattern, add `processed` **is not** `true`.
6. Check the number of matching Records that the filter shows. Click **View matches** to review sample Records. The count can change on each run as Records change.
7. Optional: for a Flow, add values that are the same for every Record in **Input Variables**.
8. In **Timing**, select **Recurring**.
9. Review the time zone shown next to **Timing**, then configure the recurrence. For example, set a daily run at 2:00 AM.
10. Click **Create**.

### Set up with the API

To create the same Schedule through the API, send a request to `POST /v1/schedules`:

```bash
curl https://api.runtype.com/v1/schedules \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "target": {
      "flowId": "YOUR_FLOW_ID",
      "recordFilter": {
        "type": "customers",
        "where": {
          "op": "and",
          "conditions": [{ "field": "processed", "op": "neq", "value": true }]
        }
      }
    },
    "trigger": {
      "type": "recurring",
      "cron": "0 2 * * *",
      "timezone": "America/Los_Angeles"
    }
  }'
```

Replace the following:

* `YOUR_API_KEY`: your Runtype API key.
* `YOUR_FLOW_ID`: the ID of the Flow to run.

A recurring trigger requires both `cron` and `timezone`. The request returns a `400` error if either is missing or invalid.

The CLI `runtype schedules create` command sets only the Flow, cron expression, and time zone. To add a Record target, save a JSON file with a `target` object that contains the `flowId` and the `recordFilter`, then run `runtype schedules update YOUR_SCHEDULE_ID --from-file schedule.json`.

### Set execution options

The API accepts `executionOptions` on a Schedule. The dashboard does not show these options.

| Option              | Range            | Default | Effect                                                              |
| ------------------- | ---------------- | ------- | ------------------------------------------------------------------- |
| `modelOverride`     | A model ID       | Not set | Runs every Record with this model instead of the Flow's model.      |
| `maxRetries`        | 0 to 10          | 3       | Sets how many times Runtype retries a failed Record in the run.     |
| `recordConcurrency` | 1 to 50          | 8       | Sets how many Records run at the same time. At most 20 run at once. |
| `flowTimeoutMs`     | 1,000 to 900,000 | Not set | Sets the time limit for each Record's execution, in milliseconds.   |
| `stepTimeoutMs`     | 1,000 to 600,000 | Not set | Sets the time limit for each step, in milliseconds.                 |

For example, `"executionOptions": { "modelOverride": "claude-haiku-4-5", "maxRetries": 2 }` runs every Record on a faster model and retries each failed Record up to twice.

## Monitor batch Schedules

Follow these steps to review scheduled runs:

1. Open **Schedules**.
2. Click the Schedule row to open its details.
3. Select **Runs** to review recent runs, statuses, and timings.
4. Open a run to inspect its results.

## Handle failures

If a Record fails before the Flow marks it as processed, the Record stays in the filter's scope. The next recurring run includes the Record again. Within a run, Runtype retries a failed Record up to 3 times by default. To change the number of retries, set `executionOptions.maxRetries`.

Use these steps to investigate and retry a failed Record:

1. Open the failed run from **Runs**.
2. Click **Record runs**, then open the failed Record to inspect its step errors.
3. Fix the Flow or the affected Record.
4. Click **Run now** to retry without waiting for the next recurring run.

### No runs appear

When a Flow Schedule's target matches no Records, Runtype skips that run. Nothing appears in **Runs**, and the next run time moves forward. With the processed pattern, this is expected after every Record is processed. It can also mean that the filter is wrong. To tell the two apart, open the Schedule, edit the filter, and check the match count.

For a Flow or Agent Schedule, **Run now** returns one of the following errors when no Records match:

* `No records match this schedule’s filter`
* `No records found with type "YOUR_RECORD_TYPE"`

### A run fails without Record runs

Every Schedule run is a batch, so the Flow must be one that batch can run. Runtype refuses to save or resume a Schedule whose Flow has a step that batch can't run, such as a top-level `wait-until` or `crawl` step. If someone adds such a step to the Flow later, each run fails once before Runtype queues any Records, and the run doesn't count toward your execution limit. The Schedule logs show the reason, such as `ineligible:wait-until`. Remove or replace the step, or pause the Schedule.

## Control batch costs

Each Record in a record-based Schedule creates a Flow or Agent execution. Model and tool calls contribute to usage cost. Use these practices:

* Use a Record Filter to process only the Records that you need.
* Choose a cadence that matches how often your data changes.
* Use a lower-cost model for batch work when it meets your quality requirements. To change the model for a Schedule without editing the Flow, set `executionOptions.modelOverride`.

### Plan limits

Your plan limits Schedules in these ways:

* **Active Schedules**: when you reach your plan's limit, the **New schedule** button is unavailable, and its tooltip reads "Active schedule limit reached. Upgrade your plan." The API returns `402` with the code `ACTIVE_SCHEDULE_LIMIT`.
* **Recurrence frequency**: the **Timing** options allow only the frequencies that your plan includes. The API returns `402` with the code `SCHEDULE_FREQUENCY_LIMIT` for a cron expression that runs more often.
* **Usage limits**: if a usage limit on your account blocks a scheduled run, Runtype skips the run and processes no Records. Nothing appears in **Runs**, and **Logs** show the entry `Schedule skipped: execution limit exceeded`.

## Next steps

Continue with these guides:

* [What are Schedules?](/user-guide/schedules/what-are-schedules): review Schedule setup and controls.
* [What are Records?](/user-guide/records/what-are-records): learn how Records store type and metadata.
* [Filtering and searching records](/user-guide/records/filtering-and-searching-records): see every filter operator.
* [Using records in flows](/user-guide/records/using-records-in-flows): update Record metadata from a Flow.
* [What are Logs?](/user-guide/logs/what-are-logs): inspect scheduled run errors and details.
* [Managing Schedules programmatically](/user-guide/schedules/managing-schedules-programmatically): manage Schedules with the API, SDK, CLI, and MCP.