# Schedules

A schedule runs a ready-made tool, an action or a platform-specific interface every day or every week at a time in your time zone, and delivers only what is new since the run before. Each run is an ordinary call, charged when it ends; one that would cost more than its limit is skipped, free. Make one with a key, in the console, or by asking your AI app (MCP `watch`).

- Page: https://socialtoai.com/docs/schedules/
- Last updated: 2026-10-25

- POST: `https://api.socialtoai.com/v1/schedules`

## Who can make one

- Any account. One that has not bought credits keeps 1 schedule, run from its free credits: when they no longer cover a run, it is paused, you get one email, and it resumes by itself after you buy credits. A second one answers HTTP 403 `plan_limit`.
- With a key that has the permission to manage schedules (set in the key's settings in the console); without it, HTTP 403 `key_scope_denied`. Or in the console: open a result and choose “Make it recurring”, then manage it on the Tasks page.
- At most 20 schedules per account that has bought credits. A schedule runs as the key that made it: when that key is revoked or expires, the schedule stops.

## From your AI app

Over MCP the same schedules are called watches. Say “watch this every morning” and your AI app calls `watch` twice: `action: "preview"` answers what will run, when, about how many credits a run and at most a month (with dollars beside them), and where new items go, and charges nothing; only after you agree, `action: "confirm"` with the preview's `token` makes it, exactly as previewed. `pause`, `resume` and `delete` take its `id`. Ask “what's new?” and `watch_news` answers what your watches found that you have not seen, newest first, for free.

A successful search or Brand buzz, Account watch, Viral finder answer over MCP may end with `watch_hint`, one line that offers to watch it daily and what a run would cost; it comes at most once an hour, and never with an error.

## Make a schedule

Name what it runs, the body of that request, when, and the most one run may cost. Making one is free: the request is quoted, and refused with HTTP 402 `max_cost_exceeded` and the quote when a run would cost more than `max_credits_per_run`.

**cURL**

```
curl https://api.socialtoai.com/v1/schedules \
  -H "Authorization: Bearer $SOCIALTOAI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Daily check",
    "action": "search",
    "input": {
      "platform": "reddit",
      "query": "saturn rings"
    },
    "frequency": "daily",
    "time": "09:00",
    "timezone": "UTC",
    "max_credits_per_run": 4
  }'
```

| Field | Type | Required | What it is |
| --- | --- | --- | --- |
| `tool` | string | One of three | A ready-made tool's id: each run runs the tool. |
| `action` | string | One of three | One of the actions, such as `search`: each run makes that call. |
| `op` | string | One of three | A platform-specific interface, written `platform.name`, as `POST /v1/call/{op}` takes it. |
| `input` | object | Yes | The body the call or the tool takes, `platform` included. `max_cost_credits` and `confirm` are left out: the schedule's own limit stands for them. |
| `name` | string \| null | No | Your own name for it, up to 80 characters. |
| `frequency` | "daily" \| "weekly" | Yes | Every day, or every week. |
| `weekday` | integer | Weekly only | 0 for Sunday to 6 for Saturday. |
| `time` | string | Yes | `HH:MM`, 24-hour, in `timezone`. |
| `timezone` | string | Yes | An IANA time zone such as `Europe/London`. The time follows its clock changes. |
| `max_credits_per_run` | integer | Yes | The most one run may cost. A run that would cost more is skipped, not charged. |
| `alert_percent` | integer | No | 1 to 1,000. A run whose main number moved by more than this percent from the last run's is an alert. |
| `paused` | boolean | Changes only | `true` pauses it; `false` takes it up again from its next time. Nothing missed meanwhile is run. |
| `email_new_items` | boolean | No | `true` emails you, after each run that found something, how many items are new and the links of the first of them. Off unless set; watches made from an AI app have it on. |

The answer holds the schedule as every route shows it:

**201 Created** (201, 0 credits)

```
{
  "request_id": "req_00000000-0000-4000-8000-000000000020",
  "schema_version": "v1",
  "schedule": {
    "id": "00000000-0000-4000-8000-000000000021",
    "name": "Daily check",
    "tool": null,
    "action": "search",
    "op": null,
    "input": {
      "platform": "reddit",
      "query": "saturn rings"
    },
    "frequency": "daily",
    "weekday": null,
    "time": "09:00",
    "timezone": "UTC",
    "max_credits_per_run": 4,
    "monthly_cap_credits": 124,
    "month_spent_credits": 0,
    "alert_percent": 20,
    "status": "active",
    "stop_reason": null,
    "email_new_items": false,
    "source": "key",
    "next_run_at": "2026-10-26T09:00:00.000Z",
    "running": false,
    "last_main_number": null,
    "last_run": null,
    "created_at": "2026-10-25T08:00:00.000Z"
  },
  "quote_credits": 2
}
```

_Example: ids and times are placeholders._

## Change, pause, run now

| Method | Path | What it does |
| --- | --- | --- |
| POST | `/v1/schedules` | Make a schedule. Answers 201 with the schedule and `quote_credits`, what a run costs now. |
| GET | `/v1/schedules` | Your account's schedules, with `max_schedules` (20) and `month_runs`. |
| GET | `/v1/schedules/{id}` | One schedule. |
| POST | `/v1/schedules/{id}` | Change it: any field but what it runs. `paused: true` pauses it, `paused: false` takes it up again. |
| POST | `/v1/schedules/{id}/delete` | Delete it. What its runs were charged stays in your usage. |
| POST | `/v1/schedules/{id}/run` | Run it now, apart from its times. Not counted in the month's cap. |
| GET | `/v1/schedules/{id}/runs` | The latest 100 times it came due: run, or skipped and why. |

A new time, and a schedule taken up again, go on from the next time after now: nothing missed meanwhile is run. What a schedule runs cannot be changed; make another schedule for that. An unknown id answers HTTP 404 `not_found`.

## What a run costs

- **A ready-made tool** is charged its scale's price and runs its whole plan each time.
- **An action or a platform-specific interface** reads its first page each time and is charged for that page. It delivers only what is new: what the last run already saw is left out.
- Of a ready-made tool's run, the items whose ids the run before did not have are what is new: `new_items` in the runs list, the email and `schedule_run.finished` count them.
- Each run is charged when it ends, at the prices in force then. A run that would cost more than `max_credits_per_run` is skipped.
- **The month's cap** is `max_credits_per_run` times the most runs a month can hold: 31 for a daily schedule, 5 for a weekly one (`monthly_cap_credits`). A scheduled run that would pass it is skipped until the next month. A run you start with `/run` is counted apart.
- Each time is run once. After an interruption on our side, only the latest time that passed is run.

## When a run is skipped

A skipped time costs nothing. Its `status` in the runs list is `skipped` and `skip_reason` says why. We email you the first time a schedule is skipped for a reason on a UTC day, unless you switched off emails about runs in the console's settings.

| skip_reason | Why |
| --- | --- |
| `previous_run_not_finished` | The run before it is still going. |
| `key_not_usable` | The key it runs as cannot be used for it now: suspended, revoked or expired, or the permission to read data or run tools switched off. |
| `not_paid` | The account has not bought credits, and runs only its first schedule. |
| `plan_limit` | A free account cannot run what it runs at this scale. |
| `unavailable` | What it runs is not offered right now. |
| `over_run_limit` | At the prices in force, a run costs more than `max_credits_per_run`. |
| `monthly_cap` | The run would pass this month's cap. |
| `insufficient_balance` | The balance does not cover the run. |
| `daily_limit_reached` | A daily cap of the key or the account is reached. |
| `rate_limited` | Too much was running at once. |
| another code | The request no longer reads as one; the value is the error code it was refused with, as in [Errors](https://socialtoai.com/docs/api/errors.md). |

## When a schedule stops

A stopped schedule does not run again; `status` is `stopped` and `stop_reason` is `key_revoked`, `key_expired` or `account_closed`. You are emailed when the key was revoked or expired. When a new price would make a run cost more than its limit, you are emailed before that price takes effect, so that you can raise the limit.

## Alerts and results

Every finished run sets its main number beside the last run's: a ready-made tool's own main number, or for an action the number of new items. When it moved by more than `alert_percent` (20 unless you set it), or is not zero after zero, the run is an alert: `alerted` is true and a `schedule.alert` event goes to your [webhooks](https://socialtoai.com/docs/webhooks.md). Every finished run also sends `schedule_run.finished`.

Each run in the runs list carries its `handle`: read its answer at `GET /v1/results/{handle}` for 24 hours, free. See [Results and handles](https://socialtoai.com/docs/api/results.md).
