Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.olostep.com/llms.txt

Use this file to discover all available pages before exploring further.

Through the Olostep /v1/monitors endpoint you can create persistent monitors that run on a fixed schedule, detect page changes, and notify you by email, webhook, or SMS.
  • Create a monitor from a natural language query
  • Run checks using natural-language schedules
  • Deliver alerts via email, webhook_url, or phone_number (SMS)
  • List, inspect, update, pause, resume, and delete monitors
  • Read monitor snapshot events from private snapshots
By default, every monitor run captures a full snapshot of the monitored page — a complete picture of its current state at that moment. If you want the monitor to surface only what’s new or changed between runs (deltas) instead of the full state, you must express that intent directly in the query.

Installation

# pip install requests

import requests

Create a monitor

Create a monitor with POST /v1/monitors. The endpoint validates your input, provisions the monitor, creates its internal schedule, and returns an active monitor object.
  • query is required. If your query includes a URL, the monitor will focus on that input URL. By default, each run takes a full snapshot of what is being monitored — a picture of the current state of the page. If you want the monitor to track only what’s new or changed between runs (for example, only new blog posts, or only price drops), you must specify that explicitly in the query; otherwise the full snapshot is captured every run.
  • frequency accepts natural-language schedule instructions and defaults to UTC when no timezone is provided.
  • Exactly one notification target is required: email, webhook_url, or phone_number (SMS).
  • Use output_schema when you want structured extraction results. (optional)

Example request

import requests
import json

API_KEY = "<YOUR_API_KEY>"
API_URL = "https://api.olostep.com/v1"

payload = {
    "query": "Track changes in https://example.com/products/widget-pro pricing and stock information",
    "frequency": "every day at 9am America/Los_Angeles",
    "email": "alerts@example.com",
    "output_schema": {
        "type": "object",
        "properties": {
            "title": {"type": "string"},
            "published_at": {"type": "string"}
        },
        "required": ["title"]
    },
    "metadata": {
        "product_id": "widget-pro",
        "team": "growth"
    }
}

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

response = requests.post(f"{API_URL}/monitors", headers=headers, json=payload)
print(response.status_code)
print(json.dumps(response.json(), indent=2))

Response

Successful monitor creation returns HTTP 202 with a monitor object:
{
  "id": "monitor_n8q2x4m1ak",
  "object": "monitor",
  "created_at": 1777983215,
  "updated_at": 1777983222,
  "fda_id": "fda_n8q2x4m1ak",
  "team_id": "team_n8q2x4m1ak",
  "status": "active",
  "query": "Track changes in https://example.com/products/widget-pro pricing and stock information",
  "frequency": "every day at 9am America/Los_Angeles",
  "cron_expression": "0 0 * * ? *",
  "notification_channel": "email",
  "notification_target": "alerts@example.com",
  "output_schema": {
    "type": "object",
    "properties": {
      "title": { "type": "string" },
      "published_at": { "type": "string" }
    },
    "required": ["title"]
  },
  "metadata": {
    "product_id": "widget-pro",
    "team": "growth"
  }
}

Structured monitor output

Set output_schema in the create request when you want monitor extraction results to follow a specific JSON structure. The schema must be valid JSON Schema.

Notification channels

Monitors support one channel per monitor:
  • email: set an email field
  • webhook: set a webhook_url field
  • sms: set a phone_number field (E.164 format, for example +14155552671)
You can set exactly one of these fields per request.

Webhook example

{
  "query": "Watch for changes in https://example.com/terms legal terms",
  "frequency": "everyday at 10:00 am",
  "webhook_url": "https://hooks.example.com/olostep-monitor"
}

SMS example

{
  "query": "Watch for changes in https://example.com/terms legal terms",
  "frequency": "everyday at 10:00 am",
  "phone_number": "+14155552671"
}

Frequencies

Set frequency in natural language, for example:
  • every day at 9am America/Los_Angeles
  • every 5 minutes
  • every 6 hours
The API interprets this schedule text and derives the cron expression automatically. If no timezone is provided, UTC is used by default.

List monitors

Retrieve all monitors for your team with GET /v1/monitors. By default, deleted monitors are filtered out. Use ?include_deleted=true to include them.
import requests
import json

API_KEY = "<YOUR_API_KEY>"
API_URL = "https://api.olostep.com/v1"

headers = {
    "Authorization": f"Bearer {API_KEY}"
}

response = requests.get(f"{API_URL}/monitors", headers=headers)
result = response.json()
print(f"Total monitors: {result['count']}")
print(json.dumps(result, indent=2))

Response shape

{
  "monitors": [
    {
      "id": "monitor_a3yk6z49p8",
      "object": "monitor",
      "created_at": 1777983215,
      "cron_expression": "13 13 * * ? *",
      "fda_id": "fda_a3yk6z49p8",
      "frequency": "daily",
      "metadata": {},
      "notification_channel": "email",
      "notification_target": "example@olostep.com",
      "query": "Gather the new blogposts from example website and send me updates with new posts.",
      "status": "active",
      "team_id": "team_a3yk6z49p8F",
      "updated_at": 1777983222
    }
  ],
  "count": 1
}

Get a monitor

Retrieve a single monitor with GET /v1/monitors/:monitor_id.
import requests
import json

API_KEY = "<YOUR_API_KEY>"
API_URL = "https://api.olostep.com/v1"
MONITOR_ID = "monitor_n8q2x4m1ak"

headers = {
    "Authorization": f"Bearer {API_KEY}"
}

response = requests.get(f"{API_URL}/monitors/{MONITOR_ID}", headers=headers)
print(json.dumps(response.json(), indent=2))

Response shape

{
  "id": "monitor_a3yk6z49p8",
  "object": "monitor",
  "created_at": 1777983215,
  "cron_expression": "13 13 * * ? *",
  "fda_id": "fda_a3yk6z49p8",
  "frequency": "daily",
  "metadata": {},
  "notification_channel": "email",
  "notification_target": "example@olostep.com",
  "query": "Gather the new blogposts from example website and send me updates with new posts.",
  "status": "active",
  "team_id": "team_a3yk6z49p8",
  "updated_at": 1777983222
}

List monitor events

Use GET /v1/monitors/:monitor_id/events to list snapshot events for a monitor. This endpoint supports pagination:
  • limit (default 25, max 100)
  • cursor (opaque pagination token from a previous response)
Events are returned newest-first. Each item includes a short-lived pre-signed snapshot_url so you can fetch private snapshot content securely.

Example

import requests
import json

API_KEY = "<YOUR_API_KEY>"
API_URL = "https://api.olostep.com/v1"
MONITOR_ID = "monitor_n8q2x4m1ak"

headers = {
    "Authorization": f"Bearer {API_KEY}"
}

response = requests.get(
    f"{API_URL}/monitors/{MONITOR_ID}/events?limit=10",
    headers=headers
)
print(json.dumps(response.json(), indent=2))

Response shape

{
  "data": [
    {
      "id": "run_v7k2p9m3",
      "run_id": "run_v7k2p9m3",
      "created": 1777960800,
      "changed": true,
      "summary": "Price changed from $49 to $45 and stock moved to low availability.",
      "snapshot_url": "https://olostep-monitor-snapshot.s3.amazonaws.com/private/key?...signature..."
    }
  ],
  "has_more": false,
  "next_cursor": null
}
If cursor is malformed, the endpoint returns:
{
  "error": "Invalid cursor."
}

Update a monitor

Update a monitor with POST /v1/monitors/:monitor_id. Supported updates:
  • metadata (merged with existing metadata; pass empty string values to delete keys)
  • frequency (natural-language schedule text, for example every weekday at 08:30 America/New_York)
If you update frequency, the API recreates the monitor schedule internally. If no timezone is included in the text, UTC is used.

Example request

import requests
import json

API_KEY = "<YOUR_API_KEY>"
API_URL = "https://api.olostep.com/v1"
MONITOR_ID = "monitor_n8q2x4m1ak"

payload = {
    "frequency": "every 2 hours",
    "metadata": {
        "owner": "ops-team",
        "deprecated_field": ""
    }
}

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

response = requests.post(
    f"{API_URL}/monitors/{MONITOR_ID}",
    headers=headers,
    json=payload
)
print(json.dumps(response.json(), indent=2))

Pause a monitor

Pause a monitor with POST /v1/monitors/:monitor_id/pause. Pausing disables the monitor’s underlying schedule so no further runs are triggered, and sets the monitor’s status to paused. The monitor row, its configuration, and its past snapshots are kept — only future scheduled executions stop. You can resume the monitor later with POST /v1/monitors/:monitor_id/resume. Only monitors with status of active can be paused. The request body is empty.
import requests
import json

API_KEY = "<YOUR_API_KEY>"
API_URL = "https://api.olostep.com/v1"
MONITOR_ID = "monitor_n8q2x4m1ak"

headers = {
    "Authorization": f"Bearer {API_KEY}"
}

response = requests.post(f"{API_URL}/monitors/{MONITOR_ID}/pause", headers=headers)
print(response.status_code)
print(json.dumps(response.json(), indent=2))

Response

On success, returns 200 with the monitor and status set to paused:
{
  "id": "monitor_n8q2x4m1ak",
  "object": "monitor",
  "status": "paused",
  "updated_at": 1777986822,
  "query": "Track changes in https://example.com/products/widget-pro pricing and stock information",
  "frequency": "every day at 9am America/Los_Angeles",
  "notification_channel": "email",
  "notification_target": "alerts@example.com"
}
Possible error responses:
  • 400monitor_id malformed, monitor already deleted, monitor not currently active, or monitor has no underlying schedule.
  • 404 — Monitor not found.
  • 409 — The monitor changed state during the pause attempt (no longer active), or the underlying schedule could not be found.

Resume a monitor

Resume a paused monitor with POST /v1/monitors/:monitor_id/resume. Resuming re-enables the monitor’s underlying schedule and sets the monitor’s status back to active. Scheduled runs continue on the existing frequency — no re-creation of the schedule is needed. Only monitors with status of paused can be resumed. The request body is empty.
import requests
import json

API_KEY = "<YOUR_API_KEY>"
API_URL = "https://api.olostep.com/v1"
MONITOR_ID = "monitor_n8q2x4m1ak"

headers = {
    "Authorization": f"Bearer {API_KEY}"
}

response = requests.post(f"{API_URL}/monitors/{MONITOR_ID}/resume", headers=headers)
print(response.status_code)
print(json.dumps(response.json(), indent=2))

Response

On success, returns 200 with the monitor and status set back to active:
{
  "id": "monitor_n8q2x4m1ak",
  "object": "monitor",
  "status": "active",
  "updated_at": 1777990422,
  "query": "Track changes in https://example.com/products/widget-pro pricing and stock information",
  "frequency": "every day at 9am America/Los_Angeles",
  "notification_channel": "email",
  "notification_target": "alerts@example.com"
}
Possible error responses:
  • 400monitor_id malformed, monitor already deleted, monitor not currently paused, or monitor has no underlying schedule.
  • 404 — Monitor not found.
  • 409 — The monitor changed state during the resume attempt (no longer paused), or the underlying schedule could not be found.

Delete a monitor

Delete a monitor with DELETE /v1/monitors/:monitor_id. Deletion is soft for the monitor row (status becomes deleted) and also removes internal scheduling/shadow-agent resources tied to that monitor.
import requests
import json

API_KEY = "<YOUR_API_KEY>"
API_URL = "https://api.olostep.com/v1"
MONITOR_ID = "monitor_n8q2x4m1ak"

headers = {
    "Authorization": f"Bearer {API_KEY}"
}

response = requests.delete(f"{API_URL}/monitors/{MONITOR_ID}", headers=headers)
print(json.dumps(response.json(), indent=2))

Example use cases

Below are practical example requests for the /v1/monitors endpoint.

Track uptime issues in the OpenAI API

Run an hourly check that watches the OpenAI API status and emails you when uptime issues are detected.
import requests
import json

API_KEY = "<YOUR_API_KEY>"
API_URL = "https://api.olostep.com/v1"

payload = {
    "query": "Track uptime issues in OpenAI API and email me at info@olostep.com",
    "frequency": "every hour",
    "email": "alerts@example.com"
}

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

response = requests.post(f"{API_URL}/monitors", headers=headers, json=payload)
print(response.status_code)
print(json.dumps(response.json(), indent=2))

Track product reviews — full snapshot per run

Monitor a product page and deliver every review to a webhook on every run. Because the query does not ask to dedupe against previous runs, each run captures a full snapshot of the reviews currently on the page (the default behavior). Use this pattern when you want the complete state every time, for example to overwrite a downstream table.
import requests
import json

API_KEY = "<YOUR_API_KEY>"
API_URL = "https://api.olostep.com/v1"

payload = {
    "query": "Monitor the reviews of this product https://www.walmart.com/reviews/product/957245477?sort=submission-desc and notify me by webhook. For each review extract the publication date, author, rating, title, and text content.",
    "frequency": "everyday at 9am",
    "webhook_url": "https://webhook.site/3fb2b00b-d66f-4c46-b778-f0c7b93d4d86",
    "output_schema": {
        "type": "object",
        "properties": {
            "reviews": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "publication_date": {"type": "string"},
                        "author": {"type": "string"},
                        "rating": {"type": "number"},
                        "title": {"type": "string"},
                        "text_content": {"type": "string"}
                    }
                },
                "required": [
                    "publication_date",
                    "author",
                    "rating",
                    "title",
                    "text_content"
                ]
            }
        }
    }
}

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

response = requests.post(f"{API_URL}/monitors", headers=headers, json=payload)
print(response.status_code)
print(json.dumps(response.json(), indent=2))

Track only new rental listings — delta from previous run

Monitor a paginated rentals search and run a multi-step pipeline that surfaces only newly appeared listings versus the previous run, then enriches and scores each one before notifying the webhook. The full workflow — paginate, detect new listings against the previous checkpoint, enrich each with crime signals for its location, assign a 1-10 score from price/location/safety, persist state, and notify — is expressed directly as ordered steps in the query. Because the natural-language steps describe both the extraction and the delta logic, no output_schema is required: the query alone drives what gets fetched, compared, enriched, scored, and delivered.
import requests
import json

API_KEY = "<YOUR_API_KEY>"
API_URL = "https://api.olostep.com/v1"

payload = {
    "query": "Monitor the first 3 pages of https://streeteasy.com/for-rent/new-jersey/price:1000-1750?sort_by=listed_desc, detect only newly appeared listings versus the previous checkpoint, enrich each new listing with crime signals for its location, assign a 1-10 overall score based on price/location/safety, persist state, and notify via webhook.",
    "frequency": "every hour",
    "webhook_url": "https://webhook.site/3fb2b00b-d66f-4c46-b778-f0c7b93d4d86"
}

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

response = requests.post(f"{API_URL}/monitors", headers=headers, json=payload)
print(response.status_code)
print(json.dumps(response.json(), indent=2))

Common validation errors

The monitor endpoints return clear validation errors for common invalid requests:
  • Missing query
  • Missing frequency, or invalid schedule instruction
  • Missing all of email, webhook_url, and phone_number
  • Providing more than one of email, webhook_url, and phone_number in the same request
  • Invalid email format
  • Invalid webhook URL (must be http or https)
  • Invalid phone number format (must be E.164, for example +14155552671)
  • Invalid output_schema (must be valid JSON Schema)
  • Invalid monitor_id format
Example error:
{
  "error": "Invalid frequency. Provide a natural-language schedule instruction."
}