# Schedules

Schedules let one webhook fire on a cron cadence without any external producer. They are the cleanest way to express heartbeat, sync, or background trigger workflows inside the same delivery and replay system as normal ingest.

## Schedule model

Scheduled webhooks require Starter+.

Each schedule belongs to one webhook and stores:

- `cronExpression` — standard 5-field cron in UTC
- an optional `name`
- an optional `payloadTemplate` (JSON object) — becomes the request body
- `status` of `active` or `paused`
- `lastFiredAt` and `nextFireAt` (Unix milliseconds)

Schedules are independent of public ingest. They create deliveries through the same delivery engine, which means the webhook's destination, transform, routing, retry policy, analytics, and DLQ behavior all apply exactly as they would for an inbound event.

## Auth model

- **Public API** `project API key`: Use `/v1/webhooks/{id}/schedules` to list, create, pause, resume, and delete schedules.
- **Dashboard** `session auth`: The [dashboard](/docs/dashboard.md) lets you create, pause, resume, and delete schedules from the webhook's schedules tab.
- **CLI**: The CLI covers schedule creation and lifecycle basics, which makes it the quickest first-party tool for scripted schedule management.

## Lifecycle

Create, pause, resume, and delete are the core operations.

Rules that matter:

- invalid cron expressions return `422`
- `nextFireAt` is computed at creation time
- pause stops future firing without deleting the schedule
- resume recomputes `nextFireAt` from the current time
- delete removes the schedule instead of archiving it

**Create a five-minute schedule**

```bash
curl https://api.hooksbase.com/v1/webhooks/wh_123/schedules \
  -X POST \
  -H "Authorization: Bearer swk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "5-minute ping",
    "cronExpression": "*/5 * * * *",
    "payloadTemplate": { "event": "heartbeat", "service": "api" }
  }'
```

## Payloads and onboarding

When `payloadTemplate` is omitted, Hooksbase sends a default JSON body with `source`, `scheduleId`, `webhookId`, `cronExpression`, and `firedAt`.

Onboarding also understands scheduled paths:

- the onboarding snapshot can include the current preferred schedule summary
- onboarding validation reuses the tracked schedule when available
- restarting or changing onboarding paths does not delete the saved schedule

If you need one-off future delivery per request instead of recurring cron, use public [ingest](/docs/ingest.md) with `x-hooksbase-deliver-at`.

## Related routes

- `GET /v1/webhooks/{id}/schedules`
- `POST /v1/webhooks/{id}/schedules`
- `DELETE /v1/webhooks/{id}/schedules/{scheduleId}`
- `POST /v1/webhooks/{id}/schedules/{scheduleId}/pause`
- `POST /v1/webhooks/{id}/schedules/{scheduleId}/resume`

## Common mistakes

- Using schedules for a one-time future delivery instead of `x-hooksbase-deliver-at`.
- Forgetting that schedules are tier-gated to Starter and above.
- Assuming pause deletes the schedule or clears its config.
- Expecting onboarding restart to clean up schedules automatically.
