Skip to main content

Schedule Endpoints

Create and manage automated, recurring scrapes via HTTP.

Create schedule

Create a new recurring schedule.
POST /api/schedules

Request body (interval-based)

{
  "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)

{
  "strategy_id": "550e8400-e29b-41d4-a716-446655440000",
  "url": "https://example.com/products",
  "cron_expression": "0 9 * * *",
  "webhook_url": "https://your-app.com/webhooks/meter"
}
FieldTypeRequiredDescription
strategy_idstringYesStrategy UUID
urlstringConditionalSingle URL to scrape (use url OR urls, not both)
urlsarrayConditionalList of URLs to scrape (use url OR urls, not both)
interval_secondsintegerConditionalInterval in seconds (minimum: 60)
cron_expressionstringConditionalCron expression
webhook_urlstringNoWebhook URL for notifications
webhook_metadataobjectNoCustom JSON metadata included in every webhook payload
webhook_secretstringNoSecret for X-Webhook-Secret header. Auto-generated if not provided when webhook_url is set
webhook_typestringNostandard or slack. Auto-detected from URL if not specified
parametersobjectNoDefault API parameter overrides for all scheduled runs (API strategies only)
Provide either interval_seconds or cron_expression, not both. Provide either url or urls, not both.

Response

{
  "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"
}
The webhook_secret is only returned in the create response. It is not included in subsequent GET responses.

### 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.
GET /api/schedules

Response

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

Example

curl https://api.meter.sh/api/schedules \
  -H "Authorization: Bearer sk_live_..."

Update schedule

Update an existing schedule.
PATCH /api/schedules/{schedule_id}

Request body

All fields are optional. Include only fields to update:
{
  "enabled": false,
  "interval_seconds": 7200,
  "webhook_url": "https://new-domain.com/webhooks",
  "webhook_metadata": {"project": "updated-project"},
  "webhook_type": "standard"
}
FieldTypeDescription
enabledbooleanEnable/disable the schedule
urlstringUpdate to a single URL
urlsarrayUpdate to multiple URLs
interval_secondsintegerNew interval in seconds
cron_expressionstringNew cron expression
webhook_urlstringNew webhook URL (or null to remove)
webhook_metadataobjectUpdate custom JSON metadata for webhook payloads
webhook_secretstringUpdate webhook secret
webhook_typestringUpdate webhook type: standard or slack
parametersobjectUpdate API parameter defaults

Response

Updated schedule object.

Example

# 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).
DELETE /api/schedules/{schedule_id}

Response

{
  "message": "Schedule deleted successfully"
}

Example

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.
POST /api/schedules/{schedule_id}/webhook-secret/regenerate

Response

{
  "schedule_id": "880e8400-e29b-41d4-a716-446655440000",
  "webhook_secret": "whsec_new_secret_here..."
}
The new secret is returned only once. Store it securely and update your webhook handler before the next delivery.

Example

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).
GET /api/schedules/{schedule_id}/changes?mark_seen=true&filter=+keyword

Query parameters

ParameterTypeRequiredDescription
mark_seenbooleanNoMark changes as seen (default: true)
filterstringNoLucene-style keyword filter for result items

Keyword filter syntax

The filter parameter uses Lucene-style syntax to filter individual result items:
SyntaxMeaningExample
+keywordRequired (AND)+rubio +tariff - items with both
keywordOptional (OR)rubio elon - items with either
-keywordExcluded (NOT)-bitcoin - items without
"phrase"Exact phrase"elon musk" - exact match
The filter applies to individual items within results, not entire jobs. Jobs with zero matching items are excluded from the response.

Response

{
  "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

# 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:
{
  "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"
}
See the Webhooks Guide for implementation details.

Error responses

StatusDescription
400Invalid request (invalid cron expression, missing required fields)
401Invalid or missing API key
404Schedule or strategy not found
500Internal server error
503Service temporarily unavailable
See REST API Errors for detailed error handling.

Next steps

Need help?

Email me at mckinnon@meter.sh