> ## Documentation Index
> Fetch the complete documentation index at: https://docs.meter.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Schedule Endpoints

> REST API endpoints for managing recurring scrape schedules

# Schedule Endpoints

Create and manage automated, recurring scrapes via HTTP.

## Create schedule

Create a new recurring schedule.

```http theme={null}
POST /api/schedules
```

### Request body (interval-based)

```json theme={null}
{
  "strategy_id": "550e8400-e29b-41d4-a716-446655440000",
  "url": "https://example.com/products",
  "interval_seconds": 3600,
  "webhook_url": "https://your-app.com/webhooks/meter"
}
```

### Request body (cron-based)

```json theme={null}
{
  "strategy_id": "550e8400-e29b-41d4-a716-446655440000",
  "url": "https://example.com/products",
  "cron_expression": "0 9 * * *",
  "webhook_url": "https://your-app.com/webhooks/meter"
}
```

| Field              | Type    | Required    | Description                                                                                    |
| ------------------ | ------- | ----------- | ---------------------------------------------------------------------------------------------- |
| `strategy_id`      | string  | Yes         | Strategy UUID                                                                                  |
| `url`              | string  | Conditional | Single URL to scrape (use `url` OR `urls`, not both)                                           |
| `urls`             | array   | Conditional | List of URLs to scrape (use `url` OR `urls`, not both)                                         |
| `interval_seconds` | integer | Conditional | Interval in seconds (minimum: 60)                                                              |
| `cron_expression`  | string  | Conditional | Cron expression                                                                                |
| `webhook_url`      | string  | No          | Webhook URL for notifications                                                                  |
| `webhook_metadata` | object  | No          | Custom JSON metadata included in every webhook payload                                         |
| `webhook_secret`   | string  | No          | Secret for `X-Webhook-Secret` header. Auto-generated if not provided when `webhook_url` is set |
| `webhook_type`     | string  | No          | `standard` or `slack`. Auto-detected from URL if not specified                                 |
| `parameters`       | object  | No          | Default API parameter overrides for all scheduled runs (API strategies only)                   |

<Note>
  Provide either `interval_seconds` or `cron_expression`, not both. Provide either `url` or `urls`, not both.
</Note>

### Response

```json theme={null}
{
  "schedule_id": "880e8400-e29b-41d4-a716-446655440000",
  "strategy_id": "550e8400-e29b-41d4-a716-446655440000",
  "url": "https://example.com/products",
  "urls": null,
  "schedule_type": "interval",
  "interval_seconds": 3600,
  "cron_expression": null,
  "enabled": true,
  "webhook_url": "https://your-app.com/webhooks/meter",
  "webhook_metadata": null,
  "webhook_secret": "whsec_a1b2c3...",
  "webhook_type": "standard",
  "parameters": null,
  "next_run_at": "2025-01-15T11:30:00Z",
  "last_run_at": null,
  "created_at": "2025-01-15T10:30:00Z",
  "updated_at": "2025-01-15T10:30:00Z"
}
```

<Note>
  The `webhook_secret` is only returned in the create response. It is not included in subsequent GET responses.
</Note>

````

### Example

```bash
# Interval-based
curl -X POST https://api.meter.sh/api/schedules \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "strategy_id": "550e8400-e29b-41d4-a716-446655440000",
    "url": "https://example.com/products",
    "interval_seconds": 3600
  }'

# Cron-based
curl -X POST https://api.meter.sh/api/schedules \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "strategy_id": "550e8400-e29b-41d4-a716-446655440000",
    "url": "https://example.com/products",
    "cron_expression": "0 9 * * *"
  }'
````

## List schedules

Get all schedules for the authenticated user.

```http theme={null}
GET /api/schedules
```

### Response

Array of schedule objects (same format as Create schedule response).

### Example

```bash theme={null}
curl https://api.meter.sh/api/schedules \
  -H "Authorization: Bearer sk_live_..."
```

## Update schedule

Update an existing schedule.

```http theme={null}
PATCH /api/schedules/{schedule_id}
```

### Request body

All fields are optional. Include only fields to update:

```json theme={null}
{
  "enabled": false,
  "interval_seconds": 7200,
  "webhook_url": "https://new-domain.com/webhooks",
  "webhook_metadata": {"project": "updated-project"},
  "webhook_type": "standard"
}
```

| Field              | Type    | Description                                      |
| ------------------ | ------- | ------------------------------------------------ |
| `enabled`          | boolean | Enable/disable the schedule                      |
| `url`              | string  | Update to a single URL                           |
| `urls`             | array   | Update to multiple URLs                          |
| `interval_seconds` | integer | New interval in seconds                          |
| `cron_expression`  | string  | New cron expression                              |
| `webhook_url`      | string  | New webhook URL (or `null` to remove)            |
| `webhook_metadata` | object  | Update custom JSON metadata for webhook payloads |
| `webhook_secret`   | string  | Update webhook secret                            |
| `webhook_type`     | string  | Update webhook type: `standard` or `slack`       |
| `parameters`       | object  | Update API parameter defaults                    |

### Response

Updated schedule object.

### Example

```bash theme={null}
# Disable schedule
curl -X PATCH https://api.meter.sh/api/schedules/880e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"enabled": false}'

# Change interval
curl -X PATCH https://api.meter.sh/api/schedules/880e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"interval_seconds": 7200}'
```

## Delete schedule

Delete a schedule (stops future jobs).

```http theme={null}
DELETE /api/schedules/{schedule_id}
```

### Response

```json theme={null}
{
  "message": "Schedule deleted successfully"
}
```

### Example

```bash theme={null}
curl -X DELETE https://api.meter.sh/api/schedules/880e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer sk_live_..."
```

## Regenerate webhook secret

Generate a new webhook secret for a schedule. The old secret is immediately invalidated.

```http theme={null}
POST /api/schedules/{schedule_id}/webhook-secret/regenerate
```

### Response

```json theme={null}
{
  "schedule_id": "880e8400-e29b-41d4-a716-446655440000",
  "webhook_secret": "whsec_new_secret_here..."
}
```

<Warning>
  The new secret is returned only once. Store it securely and update your webhook handler before the next delivery.
</Warning>

### Example

```bash theme={null}
curl -X POST https://api.meter.sh/api/schedules/880e8400-e29b-41d4-a716-446655440000/webhook-secret/regenerate \
  -H "Authorization: Bearer sk_live_..."
```

## Get schedule changes

Get unseen changes for a schedule (pull-based change detection).

```http theme={null}
GET /api/schedules/{schedule_id}/changes?mark_seen=true&filter=+keyword
```

### Query parameters

| Parameter   | Type    | Required | Description                                  |
| ----------- | ------- | -------- | -------------------------------------------- |
| `mark_seen` | boolean | No       | Mark changes as seen (default: true)         |
| `filter`    | string  | No       | Lucene-style keyword filter for result items |

### Keyword filter syntax

The `filter` parameter uses Lucene-style syntax to filter individual result items:

| Syntax     | Meaning        | Example                            |
| ---------- | -------------- | ---------------------------------- |
| `+keyword` | Required (AND) | `+rubio +tariff` - items with both |
| `keyword`  | Optional (OR)  | `rubio elon` - items with either   |
| `-keyword` | Excluded (NOT) | `-bitcoin` - items without         |
| `"phrase"` | Exact phrase   | `"elon musk"` - exact match        |

<Note>
  The filter applies to individual items within results, not entire jobs.
  Jobs with zero matching items are excluded from the response.
</Note>

### Response

```json theme={null}
{
  "schedule_id": "880e8400-e29b-41d4-a716-446655440000",
  "changes": [
    {
      "job_id": "660e8400-e29b-41d4-a716-446655440000",
      "status": "completed",
      "results": [...],
      "item_count": 12,
      "content_hash": "7f3d9a2b4c1e...",
      "completed_at": "2025-01-15T10:30:12Z",
      "seen": true
    }
  ],
  "count": 1,
  "marked_seen": true,
  "filter_applied": "+rubio +tariff"
}
```

### Example

```bash theme={null}
# Get and mark as seen
curl https://api.meter.sh/api/schedules/880e8400-e29b-41d4-a716-446655440000/changes \
  -H "Authorization: Bearer sk_live_..."

# Preview without marking
curl https://api.meter.sh/api/schedules/880e8400-e29b-41d4-a716-446655440000/changes?mark_seen=false \
  -H "Authorization: Bearer sk_live_..."

# Filter for items containing both "rubio" AND "tariff"
curl "https://api.meter.sh/api/schedules/880e8400-e29b-41d4-a716-446655440000/changes?filter=%2Brubio+%2Btariff" \
  -H "Authorization: Bearer sk_live_..."

# Filter for items containing "rubio" OR "elon"
curl "https://api.meter.sh/api/schedules/880e8400-e29b-41d4-a716-446655440000/changes?filter=rubio+elon" \
  -H "Authorization: Bearer sk_live_..."

# Filter for items with "rubio" but NOT "biden"
curl "https://api.meter.sh/api/schedules/880e8400-e29b-41d4-a716-446655440000/changes?filter=%2Brubio+-biden" \
  -H "Authorization: Bearer sk_live_..."
```

## Webhook payload

When a schedule has a webhook URL, Meter POSTs to it after each job:

```json theme={null}
{
  "job_id": "660e8400-e29b-41d4-a716-446655440000",
  "schedule_id": "880e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "results": [...],
  "item_count": 12,
  "has_changes": true,
  "content_hash": "7f3d9a2b4c1e...",
  "completed_at": "2025-01-15T10:30:12Z",
  "delivery_reason": "first_run"
}
```

`delivery_reason` is `first_run` for the first successful delivery for a
given `schedule + url`, and `content_changed` for subsequent deliveries
triggered by a content change. See
[Webhook payload formats](/api-reference/rest/webhooks#webhook-payload-formats)
for the full field reference, and the
[Webhooks Guide](/guides/webhooks) for implementation details.

## Error responses

| Status | Description                                                        |
| ------ | ------------------------------------------------------------------ |
| `400`  | Invalid request (invalid cron expression, missing required fields) |
| `401`  | Invalid or missing API key                                         |
| `404`  | Schedule or strategy not found                                     |
| `500`  | Internal server error                                              |
| `503`  | Service temporarily unavailable                                    |

See [REST API Errors](/api-reference/rest/errors) for detailed error handling.

## Next steps

<CardGroup cols={2}>
  <Card title="Webhooks Guide" icon="webhook" href="/guides/webhooks">
    Implement webhook endpoints
  </Card>

  <Card title="Pull-Based Monitoring" icon="download" href="/guides/pull-based-monitoring">
    Use the changes endpoint
  </Card>

  <Card title="Python SDK" icon="python" href="/api-reference/python/schedules">
    Use the Python SDK
  </Card>

  <Card title="Schedules Concept" icon="clock" href="/concepts/schedules">
    Learn about schedules
  </Card>
</CardGroup>

## Need help?

Email me at [mckinnon@meter.sh](mailto:mckinnon@meter.sh)
