# Event Schedules

Create clock-driven automation schedules that fire on a cron expression, fan out to a resolved audience, and trigger one automation run per row.

**Base URL:** `https://api.trustpager.com/functions/v1/api/v1`

## Endpoints

### GET /event-schedules

List all event schedules for the workspace.

**Scopes:** `schedules:read` — [full detail](./event-schedules/get-event-schedules.md)

### GET /event-schedules/:id

Retrieve a single event schedule.

**Scopes:** `schedules:read` — [full detail](./event-schedules/get-event-schedules-id.md)

### POST /event-schedules

Create a new event schedule. Required fields: name, cron_expression, audience_type, automation_id.

**Cron expression** is standard 5-field syntax: "min hour day-of-month month day-of-week".
Common 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

**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.

**Scopes:** `schedules:write` — [full detail](./event-schedules/post-event-schedules.md)

### PATCH /event-schedules/:id

Partial update — modify name, description, is_active, cron_expression, timezone, audience_type, audience_filter, automation_id, end_at, or max_runs. Changing cron_expression or timezone automatically recomputes next_run_at.

**Scopes:** `schedules:write` — [full detail](./event-schedules/patch-event-schedules-id.md)

### DELETE /event-schedules/:id

Permanently delete an event schedule. The linked automation is NOT deleted. This cannot be undone.

**Scopes:** `schedules:delete` — [full detail](./event-schedules/delete-event-schedules-id.md)

### POST /event-schedules/preview-cron

Validate a cron expression and preview the next N fire times in a specified timezone. Does NOT create any schedule. Use to confirm a pattern before saving.

**Scopes:** `schedules:read` — [full detail](./event-schedules/post-event-schedules-preview-cron.md)

### POST /event-schedules/:id/fire-now

Manually fire an event schedule immediately. Resolves the current audience and triggers one automation run per row. Does NOT advance next_run_at, increment run_count, or respect end_at/max_runs limits. Useful for testing, ad-hoc sends, or recovering from a missed fire.

**Scopes:** `schedules:write` — [full detail](./event-schedules/post-event-schedules-id-fire-now.md)

### GET /event-schedules/:id/audience-preview

Preview the audience a schedule WOULD resolve to right now -- returns the total count and a configurable sample of trigger_data rows, without firing anything. Use before enabling a schedule to verify the filter targets the right rows.

**Scopes:** `schedules:read` — [full detail](./event-schedules/get-event-schedules-id-audience-preview.md)

### GET /event-schedules/:id/runs

List historical fire records for a schedule. Shows audience_size, runs_triggered, runs_failed, status (completed/partial/failed), and timing. Use to verify schedules are firing, debug failures, or audit history. Supports cursor pagination ordered by fired_at descending.

**Scopes:** `schedules:read` — [full detail](./event-schedules/get-event-schedules-id-runs.md)
