# POST /auto-schedules

**Resource:** [Auto Schedules](./auto-schedules.md)  
**Scopes:** `schedules:write`  
**Write operation:** yes

Create a new auto schedule. Required fields: name, audience_type, automation_id, and exactly one schedule input (see below).

**Specify the schedule in one of two ways:**

**Option A -- Structured (recommended for AI agents):** Provide time_of_day ("HH:MM", e.g. "08:00") plus optional days_of_week (array of ints 0-6, where 0=Sunday and 6=Saturday) and timezone. The server derives the cron expression automatically.
- Example: time_of_day "08:00", days_of_week [1,2,3,4,5], timezone "Australia/Melbourne" -- stores cron "0 8 * * 1,2,3,4,5"

**Option B -- Raw cron:** Provide cron_expression (standard 5-field syntax) and timezone. Use this for patterns that time_of_day cannot express, such as every-N-minutes, twice-daily, or monthly schedules.
- Example: cron_expression "0 9,17 * * *", timezone "Australia/Sydney" -- fires 9am and 5pm daily

If both are provided, cron_expression wins. Cron is the canonical stored form -- the response always includes cron_expression regardless of which input option was used.

**Common cron patterns:**
- "*/15 * * * *" -- every 15 minutes
- "0 * * * *" -- every hour
- "0 9 * * *" -- daily at 9am
- "0 9 * * 1-5" -- weekdays at 9am
- "0 9 * * 1" -- every Monday at 9am
- "0 9,17 * * *" -- 9am and 5pm daily
- "0 9 1 * *" -- 1st of every month at 9am

**audience_type** controls who receives a run:
- "users" -- one run per staff member (with optional role/user_ids filter)
- "tasks_by_assignee" -- one run per assignee who has open tasks (digest pattern)
- "contacts" -- one run per matching contact
- "deals" -- one run per matching deal

**audience_filter** is type-specific JSON:
- users: { "roles": ["client_editor"], "user_ids": ["uuid"] }
- tasks_by_assignee: { "statuses": ["open"], "include_overdue_only": true, "max_tasks_per_user": 20 }
- contacts: { "contact_type": "lead", "has_email": true, "limit": 500 }
- deals: { "status": "open", "stale_days": 14, "pipeline_id": "uuid", "stage_ids": ["uuid"], "limit": 200 }

Optionally set end_at (ISO timestamp) to stop firing after a date, or max_runs (integer) to auto-deactivate after N fires.

## Parameters

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| `name` | body | string | yes | Schedule name |
| `audience_type` | body | string | yes | One of: users, tasks_by_assignee, contacts, deals |
| `automation_id` | body | uuid | yes | UUID of the automation to fire. Must belong to this workspace. |
| `time_of_day` | body | string | no | Schedule time in "HH:MM" format (e.g. "08:00"). Use with optional days_of_week and timezone. Server derives cron_expression automatically. Required if cron_expression is not provided. |
| `days_of_week` | body | array | no | Array of integers 0-6 (0=Sunday, 6=Saturday). Used with time_of_day. Omit or pass empty array for daily. Example: [1,2,3,4,5] for weekdays. |
| `cron_expression` | body | string | no | Standard 5-field cron expression. Use for patterns time_of_day cannot express (every-N-minutes, twice-daily, monthly, etc.). If both time_of_day and cron_expression are provided, cron_expression wins. |
| `timezone` | body | string | no | IANA timezone, e.g. "Australia/Sydney" (default). Used with both input options. |
| `description` | body | string | no | Optional description |
| `is_active` | body | boolean | no | Whether the schedule fires automatically (default true) |
| `audience_filter` | body | object | no | Audience-specific filter JSON (see description above) |
| `end_at` | body | string | no | ISO timestamp after which the schedule stops firing |
| `max_runs` | body | number | no | Auto-deactivate after firing this many times |

## Request example

```bash
# Option A -- structured (AI-agent-friendly)
curl -X POST \
  "https://api.trustpager.com/functions/v1/api/v1/auto-schedules" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-key-here" \
  -d '{
    "name": "Morning Task Digest",
    "time_of_day": "08:00",
    "days_of_week": [1, 2, 3, 4, 5],
    "timezone": "Australia/Melbourne",
    "audience_type": "tasks_by_assignee",
    "audience_filter": {},
    "automation_id": "YOUR_AUTOMATION_ID"
  }'

# Option B -- raw cron (for complex patterns)
curl -X POST \
  "https://api.trustpager.com/functions/v1/api/v1/auto-schedules" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-key-here" \
  -d '{
    "name": "Daily Staff Digest",
    "cron_expression": "0 9 * * 1-5",
    "timezone": "Australia/Sydney",
    "audience_type": "users",
    "automation_id": "YOUR_AUTOMATION_ID"
  }'
```

## Response example

```json
{
  "data": {
    "id": "a1b2c3d4-...",
    "name": "Daily Staff Digest",
    "is_active": true,
    "cron_expression": "0 9 * * 1-5",
    "timezone": "Australia/Sydney",
    "audience_type": "users",
    "audience_filter": {},
    "automation_id": "b2c3d4e5-...",
    "next_run_at": "2026-04-21T23:00:00+00:00",
    "last_run_at": null,
    "run_count": 0,
    "max_runs": null,
    "end_at": null,
    "created_at": "2026-04-19T10:00:00Z",
    "updated_at": "2026-04-19T10:00:00Z"
  },
  "meta": { "credits_remaining": 9988 }
}
```

---
Base URL: `https://api.trustpager.com/functions/v1/api/v1` — Auth: `Authorization: Bearer YOUR_API_KEY`