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

# Monitors

> Monitor pagina’s volgens een schema en stuur meldingen bij wijzigingen

Via de Olostep `/v1/monitors` endpoint kun je permanente monitors maken die op een vast schema draaien, paginawijzigingen detecteren en je op de hoogte stellen via e-mail, Slack, SMS of een speciale webhook.

* Maak een monitor van een natuurlijke taal `query`
* Beperk bronnen met `source_policy`
* Voer controles uit op schema's in natuurlijke taal (minimaal elke 10 minuten, UTC)
* Configureer `notification.channels` en optionele `webhook` levering
* Stream provisioning voortgang met Server-Sent Events (`?stream=1`)
* Lijst, inspecteer, update, pauzeer, hervat en verwijder monitors
* Lees snapshot events, planningsartefacten, run logs en live agent logs

Standaard legt elke monitor run een **volledige snapshot** vast van de gemonitorde pagina — een compleet beeld van de huidige staat op dat moment. Als je wilt dat de monitor alleen toont wat nieuw of gewijzigd is tussen runs (delta's) in plaats van de volledige staat, geef dat dan aan in de `query`.

## Installatie

<CodeGroup>
  ```python Python theme={null}
  # pip install requests

  import requests
  ```

  ```js Node theme={null}
  // npm install node-fetch

  // ESM
  import fetch from 'node-fetch'

  // CommonJS
  const fetch = require('node-fetch')
  ```

  ```bash cURL theme={null}
  # macOS: ingebouwde curl is prima
  ```
</CodeGroup>

## Maak een monitor

Maak een monitor met `POST /v1/monitors`. De API valideert je invoer, reserveert een monitorrecord, voorziet een schaduwagent, genereert een workflow specificatie, plaatst DAG planning in de wachtrij en creëert een terugkerend schema.

* `query` is vereist — beschrijf wat je wilt monitoren in natuurlijke taal.
* `frequency` is optioneel en standaard `elke uur`. Gebruik planningszinnen zoals `elke dag om 9 uur` (schema's draaien in **UTC**; minimale interval is **10 minuten**).
* `source_policy` beperkt optioneel `include_urls`, `exclude_urls`, `include_domains` en `exclude_domains`.
* `notification` configureert wanneer en hoe te waarschuwen (`events` + `channels`). Kanaallevering wordt op runtime opgelost door de monitor pipeline — je geeft geen ontvangers door aan de DAG.
* `webhook` is een apart object (`{ "url": "https://…" }`) voor HTTP callbacks naast `notification.channels`.
* `output_schema` dwingt optioneel gestructureerde extractie af (geldige JSON Schema).

De create response is HTTP `202` met `status: provisioning`. De monitor gaat naar `active` nadat planning `tracked` doelen oplost. Poll `GET /v1/monitors/:monitor_id` of geef `?stream=1` (of `Accept: text/event-stream`) door om provisioning fases en spec reasoning tokens over SSE te volgen.

### Voorbeeldverzoek

Je hebt alleen `query` en `frequency` nodig. Notificatiekanalen en webhooks kunnen later worden toegevoegd met `POST /v1/monitors/:monitor_id`.

<CodeGroup>
  ```python Python theme={null}
  import requests
  import json

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

  payload = {
      "query": "Stel me op de hoogte wanneer een nieuwe startup lanceert op Y Combinator Launches",
      "frequency": "elke 20 minuten",
  }

  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))
  ```

  ```js Node theme={null}
  const API_URL = 'https://api.olostep.com/v1'

  const res = await fetch(`${API_URL}/monitors`, {
    method: 'POST',
    headers: { 'Authorization': 'Bearer <YOUR_API_KEY>', 'Content-Type': 'application/json' },
    body: JSON.stringify({
      query: 'Stel me op de hoogte wanneer een nieuwe startup lanceert op Y Combinator Launches',
      frequency: 'elke 20 minuten',
    }),
  })

  console.log(res.status)
  console.log(await res.json())
  ```

  ```bash cURL theme={null}
  curl -sS -X POST "https://api.olostep.com/v1/monitors" \
    -H "Authorization: Bearer $OLOSTEP_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "query": "Stel me op de hoogte wanneer een nieuwe startup lanceert op Y Combinator Launches",
      "frequency": "elke 20 minuten"
    }'
  ```
</CodeGroup>

### Respons

Succesvolle creatie (niet-streaming) retourneert HTTP `202` met een monitor object. `tracked` is leeg totdat planning is voltooid; poll `GET /v1/monitors/:monitor_id` totdat `status` `active` is en `tracked.urls` is gevuld.

```json theme={null}
{
  "id": "monitor_biglavgvq3",
  "object": "monitor",
  "query": "Stel me op de hoogte wanneer een nieuwe startup lanceert op Y Combinator Launches",
  "tracked": {
    "type": null,
    "urls": [],
    "web_query": null
  },
  "source_policy": {},
  "schedule": {
    "frequency": "elke 20 minuten",
    "cron": "7/20 * * * ? *",
    "timezone": "UTC",
    "next_run_at": null
  },
  "notification": {
    "events": [],
    "channels": []
  },
  "webhook": null,
  "output_schema": {},
  "status": "provisioning",
  "error_message": null,
  "last_run": null,
  "agent": {
    "id": "agent_forward_deployed_0_fda_nlkxhr5kto"
  },
  "metadata": {},
  "created": 1780063068,
  "updated": 1780063071
}
```

### Gestructureerde monitor output

Stel `output_schema` in wanneer je wilt dat extractieresultaten een specifieke JSON structuur volgen. Het schema moet een geldige JSON Schema zijn.

### Provisioning stream

Voeg `?stream=1` toe of stuur `Accept: text/event-stream` om SSE events te ontvangen terwijl de monitor wordt aangemaakt:

| Event             | Beschrijving                                                 |
| ----------------- | ------------------------------------------------------------ |
| `phase`           | Provisioning stap (`running`, `done`, of `failed`)           |
| `reasoning_token` | Incrementele spec-design tekst                               |
| `reasoning_reset` | Truncateert gebufferde reasoning na een mislukte LLM poging  |
| `complete`        | Definitief monitor object (zelfde vorm als de `202` respons) |
| `error`           | Terminale fout                                               |

## Notificaties en webhooks

Meldingen worden geconfigureerd op het monitor record en opgelost tijdens runtime — embed geen kanaaldoelen in de monitoring `query`.

### `notification`

| Veld       | Beschrijving                                                                                                                                                                                                             |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `events`   | Welke run-uitkomsten moeten levering activeren. Zie [notificatie events](#notification-events) hieronder. Als je `channels` instelt en `events` weglaat, is de standaardinstelling zowel `changed` als `first_snapshot`. |
| `channels` | Lijst van `{ "type", "target", "events"? }` objecten                                                                                                                                                                     |

#### Notificatie events

Gebruik `events` om aan te geven **wanneer** je op de hoogte wilt worden gesteld. Toegestane waarden:

| Event            | Betekenis                                                                                                                                                                                              |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `changed`        | Meld wanneer de monitor een **wijziging** detecteert ten opzichte van de vorige snapshot (bijvoorbeeld nieuwe inhoud, bijgewerkte prijs, of een verschil dat de pipeline classificeert als gewijzigd). |
| `first_snapshot` | Meld wanneer de monitor zijn **eerste snapshot** neemt — de initiële baseline run die de huidige inhoud opslaat voordat latere vergelijkingen worden gemaakt.                                          |

Je kunt een of beide opnemen. Bijvoorbeeld, `["changed"]` waarschuwt alleen bij updates na de baseline; `["first_snapshot"]` bevestigt de setup zonder te wachten op een verschil; `["changed", "first_snapshot"]` dekt beide.

Per-kanaal `events` op een kanaalobject gebruikt dezelfde waarden en overschrijft de lijst op het hoogste niveau alleen voor dat kanaal.

Ondersteunde kanaaltypen:

| `type`  | `target` formaat                                   |
| ------- | -------------------------------------------------- |
| `email` | Geldig e-mailadres                                 |
| `slack` | Slack inkomende webhook URL                        |
| `sms`   | E.164 telefoonnummer (bijvoorbeeld `+14155552671`) |

### `webhook`

Afzonderlijk van `notification.channels`, ontvangt `webhook.url` HTTP POST payloads wanneer de monitor je callback URL activeert. Je kunt zowel een webhook als kanaalnotificaties op dezelfde monitor gebruiken.

### Voorbeelden

Alleen e-mail:

```json theme={null}
{
  "query": "Houd wijzigingen bij op https://example.com/terms",
  "frequency": "elke dag om 10 uur",
  "notification": {
    "events": ["changed"],
    "channels": [
      { "type": "email", "target": "legal@example.com" }
    ]
  }
}
```

Webhook callback:

```json theme={null}
{
  "query": "Houd wijzigingen bij op https://example.com/terms",
  "frequency": "elke dag om 10 uur",
  "webhook": {
    "url": "https://hooks.example.com/olostep-monitor"
  }
}
```

SMS:

```json theme={null}
{
  "query": "Waarschuw me wanneer https://status.example.com een incident toont",
  "frequency": "elke uur",
  "notification": {
    "channels": [
      { "type": "sms", "target": "+14155552671" }
    ]
  }
}
```

## Bronbeleid

Gebruik `source_policy` om te beperken welke URL's en domeinen de planner mag gebruiken.

```json theme={null}
{
  "source_policy": {
    "include_urls": ["https://example.com/pricing"],
    "exclude_domains": ["ads.example.com"]
  }
}
```

## Frequenties

Stel `frequency` in natuurlijke taal in, bijvoorbeeld:

* `elke uur` (standaard wanneer weggelaten)
* `elke dag om 9 uur`
* `elke werkdag om 14:30`

Regels:

* Moet leesbaar zijn als plannings taal (niet een willekeurige monitor vraag).
* Minimale interval: **elke 10 minuten**.
* Schema's worden opgeslagen en uitgevoerd in **UTC** (`schedule.timezone` is `UTC`).
* Maximale lengte: 50 tekens.

De API leidt een cron-expressie af van je `frequency` tekst en toont deze op `schedule.cron`. Wanneer de monitor `active` is, toont `schedule.next_run_at` de volgende run in ISO 8601.

## Lijst monitors

Haal alle monitors voor je team op met `GET /v1/monitors`.

Standaard worden verwijderde monitors eruit gefilterd. Gebruik `?include_deleted=true` om ze op te nemen.

<CodeGroup>
  ```python Python theme={null}
  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"Totaal aantal monitors: {result['count']}")
  print(json.dumps(result, indent=2))
  ```

  ```js Node theme={null}
  const API_URL = 'https://api.olostep.com/v1'

  const res = await fetch(`${API_URL}/monitors`, {
    headers: { 'Authorization': 'Bearer <YOUR_API_KEY>' }
  })
  const result = await res.json()

  console.log(`Totaal aantal monitors: ${result.count}`)
  console.log(result.monitors)
  ```

  ```bash cURL theme={null}
  curl -s -X GET "https://api.olostep.com/v1/monitors" \
    -H "Authorization: Bearer $OLOSTEP_API_KEY"
  ```
</CodeGroup>

### Responsvorm

```json theme={null}
{
  "monitors": [
    {
      "id": "monitor_0wj35czpn7",
      "object": "monitor",
      "query": "Houd de AirOps blog in de gaten voor nieuwe blogposts",
      "tracked": {
        "type": "urls",
        "urls": ["https://www.airops.com/blog"],
        "web_query": null
      },
      "source_policy": {},
      "schedule": {
        "frequency": "elke uur",
        "cron": "2 * * * ? *",
        "timezone": "UTC",
        "next_run_at": null
      },
      "notification": {
        "channels": [],
        "events": []
      },
      "webhook": null,
      "output_schema": {},
      "status": "paused",
      "error_message": null,
      "last_run": null,
      "agent": { "id": "agent_forward_deployed_0_fda_x4822l9h3i" },
      "metadata": {},
      "created": 1780062756,
      "updated": 1780063025
    },
    {
      "id": "monitor_biglavgvq3",
      "object": "monitor",
      "query": "Stel me op de hoogte wanneer een nieuwe startup lanceert op Y Combinator Launches",
      "tracked": {
        "type": "urls",
        "urls": ["https://www.ycombinator.com/launches/"],
        "web_query": null
      },
      "source_policy": {},
      "schedule": {
        "frequency": "elke 20 minuten",
        "cron": "7/20 * * * ? *",
        "timezone": "UTC",
        "next_run_at": "2026-05-29T14:27:00.000Z"
      },
      "notification": {
        "channels": [],
        "events": []
      },
      "webhook": null,
      "output_schema": {},
      "status": "active",
      "error_message": null,
      "last_run": null,
      "agent": { "id": "agent_forward_deployed_0_fda_nlkxhr5kto" },
      "metadata": {},
      "created": 1780063068,
      "updated": 1780063141
    }
  ],
  "count": 5
}
```

## Haal een monitor op

Haal een enkele monitor op met `GET /v1/monitors/:monitor_id`.

De respons bevat `last_run` (laatste snapshot samenvatting) en `total_count` (aantal snapshots) tenzij je `include_total_count=false` doorgeeft. Voeg `include-diagram=true` toe om een `mermaid_diagram` van de monitor DAG op te nemen.

<CodeGroup>
  ```python Python theme={null}
  import requests
  import json

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

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

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

  ```js Node theme={null}
  const API_URL = 'https://api.olostep.com/v1'
  const monitorId = 'monitor_biglavgvq3'

  const res = await fetch(`${API_URL}/monitors/${monitorId}`, {
    headers: { 'Authorization': 'Bearer <YOUR_API_KEY>' }
  })
  console.log(await res.json())
  ```

  ```bash cURL theme={null}
  curl -s -X GET "https://api.olostep.com/v1/monitors/monitor_biglavgvq3" \
    -H "Authorization: Bearer $OLOSTEP_API_KEY"
  ```
</CodeGroup>

### Responsvorm

```json theme={null}
{
  "id": "monitor_biglavgvq3",
  "object": "monitor",
  "query": "Stel me op de hoogte wanneer een nieuwe startup lanceert op Y Combinator Launches",
  "tracked": {
    "type": "urls",
    "urls": ["https://www.ycombinator.com/launches/"],
    "web_query": null
  },
  "source_policy": {},
  "schedule": {
    "frequency": "elke 20 minuten",
    "cron": "7/20 * * * ? *",
    "timezone": "UTC",
    "next_run_at": "2026-05-29T14:27:00.000Z"
  },
  "notification": {
    "channels": [],
    "events": []
  },
  "webhook": null,
  "output_schema": {},
  "status": "active",
  "error_message": null,
  "last_run": {
    "id": "run_iwsoafcpyx",
    "status": "completed",
    "change_detected": false,
    "ran_at": "2026-05-29T14:03:15.963Z"
  },
  "agent": {
    "id": "agent_forward_deployed_0_fda_nlkxhr5kto"
  },
  "metadata": {},
  "created": 1780063068,
  "updated": 1780063141,
  "total_count": 1
}
```

## Lijst monitor events

Gebruik `GET /v1/monitors/:monitor_id/events` om snapshot events voor een monitor op te sommen.

Paginering:

* `limit` (standaard `25`, max `100`)
* `cursor` (ondoorzichtige token van `next_cursor`)
* `count_only=true` retourneert alleen `{ "total_count": N }`

Events worden nieuw-naar-oud geretourneerd. Elk item bevat een kortlevende vooraf ondertekende `snapshot_url`.

<CodeGroup>
  ```python Python theme={null}
  import requests
  import json

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

  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))
  ```

  ```js Node theme={null}
  const API_URL = 'https://api.olostep.com/v1'
  const monitorId = 'monitor_biglavgvq3'

  const res = await fetch(`${API_URL}/monitors/${monitorId}/events?limit=10`, {
    headers: { 'Authorization': 'Bearer <YOUR_API_KEY>' }
  })
  console.log(await res.json())
  ```

  ```bash cURL theme={null}
  curl -s -X GET "https://api.olostep.com/v1/monitors/monitor_biglavgvq3/events?limit=10" \
    -H "Authorization: Bearer $OLOSTEP_API_KEY"
  ```
</CodeGroup>

### Responsvorm

```json theme={null}
{
  "data": [
    {
      "id": "run_iwsoafcpyx",
      "run_id": "run_iwsoafcpyx",
      "created": 1780063395,
      "changed": false,
      "summary": "Eerste snapshot van deze monitor is genomen. Huidige inhoud opgeslagen als baseline.",
      "snapshot_url": "https://olostep-monitor-snapshots.s3.amazonaws.com/monitor_biglavgvq3/run_iwsoafcpyx_snapshot.json?X-Amz-Expires=600&..."
    }
  ],
  "has_more": false,
  "next_cursor": null,
  "total_count": 1
}
```

## Haal monitor planning op

Gebruik `GET /v1/monitors/:monitor_id/planning` om de FDA workflow specificatie en planner DAG na provisioning te inspecteren.

```json theme={null}
{
  "spec": {
    "saved_at": "2026-05-29T12:00:00.000000+00:00",
    "status": "complete",
    "goal": "Volg prijzen op example.com",
    "reasoning": "...",
    "constraints": "...",
    "assumptions": "...",
    "input": { "query": "...", "urls": ["https://www.ycombinator.com/launches/"] },
    "output": { "type": "free_text" },
    "chat_history": []
  },
  "dag": {
    "user_query": "...",
    "graph": { "nodes": [], "edges": [] },
    "has_unresolved": false,
    "unresolved": [],
    "validation": { "is_valid": true, "attempts": 1, "history": [] }
  }
}
```

## Haal een monitor run op

Gebruik `GET /v1/monitors/:monitor_id/runs/:run_id` voor snapshot metadata en geparseerde agent log events voor één uitvoering (`run_id` moet beginnen met `run_`).

```json theme={null}
{
  "monitor_id": "monitor_biglavgvq3",
  "run_id": "run_v7k2p9m3",
  "snapshot": { "changed": true, "summary": "..." },
  "log_group": "/aws/ecs/olostep-agents/...",
  "events": [
    {
      "id": "...",
      "ts": 1777960800123,
      "message": "Run run_v7k2p9m3 voltooid. Bestanden geüpload: 2",
      "event": { "type": "run_complete", "run_id": "run_v7k2p9m3", "files_uploaded": 2 }
    }
  ]
}
```

## Stream agent logs

Gebruik `GET /v1/monitors/:monitor_id/agent-logs?stream=1` (of `Accept: text/event-stream`) om CloudWatch logs voor de agent van de monitor te volgen, gefilterd op deze `monitor_id`.

Optionele queryparameter `since` is een milliseconde-timestamp (standaard: 30 minuten geleden).

SSE event types: `ready`, `log`, `heartbeat`, `error`.

## Update een monitor

Update een monitor met `POST /v1/monitors/:monitor_id`.

Ondersteunde velden (inclusief alleen wat je wilt wijzigen):

* `metadata` — samengevoegd met bestaande sleutels; lege stringwaarden verwijderen sleutels
* `frequency` — hercreëert het interne schema en stelt `status` terug naar `active`
* `notification` — vervangt het gehele notificatieobject
* `webhook` — geef `null` door om te verwijderen

Retourneert `409` terwijl `status` `provisioning` is.

Wanneer je `notification.channels` toevoegt zonder `events`, stelt de API `events` standaard in op `["changed", "first_snapshot"]`.

### Voeg e-mailnotificatie toe

<CodeGroup>
  ```python Python theme={null}
  import requests
  import json

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

  payload = {
      "notification": {
          "channels": [
              {"type": "email", "target": "you@example.com"}
          ]
      }
  }

  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))
  ```

  ```js Node theme={null}
  const API_URL = 'https://api.olostep.com/v1'
  const monitorId = 'monitor_biglavgvq3'

  const res = await fetch(`${API_URL}/monitors/${monitorId}`, {
    method: 'POST',
    headers: { 'Authorization': 'Bearer <YOUR_API_KEY>', 'Content-Type': 'application/json' },
    body: JSON.stringify({
      notification: {
        channels: [{ type: 'email', target: 'you@example.com' }]
      }
    })
  })
  console.log(await res.json())
  ```

  ```bash cURL theme={null}
  curl -s -X POST "https://api.olostep.com/v1/monitors/monitor_biglavgvq3" \
    -H "Authorization: Bearer $OLOSTEP_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "notification": {
        "channels": [
          { "type": "email", "target": "you@example.com" }
        ]
      }
    }'
  ```
</CodeGroup>

```json theme={null}
{
  "id": "monitor_biglavgvq3",
  "object": "monitor",
  "query": "Stel me op de hoogte wanneer een nieuwe startup lanceert op Y Combinator Launches",
  "tracked": {
    "type": "urls",
    "urls": ["https://www.ycombinator.com/launches/"],
    "web_query": null
  },
  "source_policy": {},
  "schedule": {
    "frequency": "elke 20 minuten",
    "cron": "7/20 * * * ? *",
    "timezone": "UTC",
    "next_run_at": "2026-05-29T14:27:00.000Z"
  },
  "notification": {
    "events": ["changed", "first_snapshot"],
    "channels": [
      { "type": "email", "target": "you@example.com" }
    ]
  },
  "webhook": null,
  "output_schema": {},
  "status": "active",
  "error_message": null,
  "last_run": null,
  "agent": { "id": "agent_forward_deployed_0_fda_nlkxhr5kto" },
  "metadata": {},
  "created": 1780063068,
  "updated": 1780064634
}
```

### Voeg webhook toe

<CodeGroup>
  ```python Python theme={null}
  import requests
  import json

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

  payload = {
      "webhook": { "url": "https://webhook.site/your-unique-id" }
  }

  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))
  ```

  ```js Node theme={null}
  const API_URL = 'https://api.olostep.com/v1'
  const monitorId = 'monitor_biglavgvq3'

  const res = await fetch(`${API_URL}/monitors/${monitorId}`, {
    method: 'POST',
    headers: { 'Authorization': 'Bearer <YOUR_API_KEY>', 'Content-Type': 'application/json' },
    body: JSON.stringify({
      webhook: { url: 'https://webhook.site/your-unique-id' }
    })
  })
  console.log(await res.json())
  ```

  ```bash cURL theme={null}
  curl -s -X POST "https://api.olostep.com/v1/monitors/monitor_biglavgvq3" \
    -H "Authorization: Bearer $OLOSTEP_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "webhook": { "url": "https://webhook.site/your-unique-id" }
    }'
  ```
</CodeGroup>

```json theme={null}
{
  "id": "monitor_biglavgvq3",
  "object": "monitor",
  "query": "Stel me op de hoogte wanneer een nieuwe startup lanceert op Y Combinator Launches",
  "tracked": {
    "type": "urls",
    "urls": ["https://www.ycombinator.com/launches/"],
    "web_query": null
  },
  "source_policy": {},
  "schedule": {
    "frequency": "elke 20 minuten",
    "cron": "7/20 * * * ? *",
    "timezone": "UTC",
    "next_run_at": "2026-05-29T14:47:00.000Z"
  },
  "notification": {
    "channels": [
      { "type": "email", "target": "you@example.com" }
    ],
    "events": ["changed", "first_snapshot"]
  },
  "webhook": {
    "url": "https://webhook.site/your-unique-id"
  },
  "output_schema": {},
  "status": "active",
  "error_message": null,
  "last_run": null,
  "agent": { "id": "agent_forward_deployed_0_fda_nlkxhr5kto" },
  "metadata": {},
  "created": 1780063068,
  "updated": 1780065538
}
```

## Pauzeer een monitor

Pauzeer een monitor met `POST /v1/monitors/:monitor_id/pause`.

Pauzeren schakelt het onderliggende schema uit en stelt `status` in op `paused`. Alleen monitors met `status: active` kunnen worden gepauzeerd. Het verzoeklichaam is leeg.

<CodeGroup>
  ```python Python theme={null}
  import requests
  import json

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

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

  ```js Node theme={null}
  const API_URL = 'https://api.olostep.com/v1'
  const monitorId = 'monitor_biglavgvq3'

  const res = await fetch(`${API_URL}/monitors/${monitorId}/pause`, {
    method: 'POST',
    headers: { 'Authorization': 'Bearer <YOUR_API_KEY>' }
  })
  console.log(res.status)
  console.log(await res.json())
  ```

  ```bash cURL theme={null}
  curl -s -X POST "https://api.olostep.com/v1/monitors/monitor_biglavgvq3/pause" \
    -H "Authorization: Bearer $OLOSTEP_API_KEY"
  ```
</CodeGroup>

Bij succes retourneert `200` met de monitor en `status: paused`. `schedule.next_run_at` is `null` terwijl gepauzeerd.

## Hervat een monitor

Hervat een gepauzeerde monitor met `POST /v1/monitors/:monitor_id/resume`.

Hervatten schakelt het schema weer in en stelt `status` terug naar `active`. Alleen `paused` monitors kunnen worden hervat.

<CodeGroup>
  ```python Python theme={null}
  import requests
  import json

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

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

  ```js Node theme={null}
  const API_URL = 'https://api.olostep.com/v1'
  const monitorId = 'monitor_biglavgvq3'

  const res = await fetch(`${API_URL}/monitors/${monitorId}/resume`, {
    method: 'POST',
    headers: { 'Authorization': 'Bearer <YOUR_API_KEY>' }
  })
  console.log(res.status)
  console.log(await res.json())
  ```

  ```bash cURL theme={null}
  curl -s -X POST "https://api.olostep.com/v1/monitors/monitor_biglavgvq3/resume" \
    -H "Authorization: Bearer $OLOSTEP_API_KEY"
  ```
</CodeGroup>

## Verwijder een monitor

Verwijder een monitor met `DELETE /v1/monitors/:monitor_id`.

Verwijdering soft-verwijdert de monitor rij (`status: deleted`) en verwijdert zijn schema en schaduwagent resources.

<CodeGroup>
  ```python Python theme={null}
  import requests
  import json

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

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

  ```js Node theme={null}
  const API_URL = 'https://api.olostep.com/v1'
  const monitorId = 'monitor_biglavgvq3'

  const res = await fetch(`${API_URL}/monitors/${monitorId}`, {
    method: 'DELETE',
    headers: { 'Authorization': 'Bearer <YOUR_API_KEY>' }
  })
  console.log(await res.json())
  ```

  ```bash cURL theme={null}
  curl -s -X DELETE "https://api.olostep.com/v1/monitors/monitor_biglavgvq3" \
    -H "Authorization: Bearer $OLOSTEP_API_KEY"
  ```
</CodeGroup>

## Monitor status

| Status         | Betekenis                                                           |
| -------------- | ------------------------------------------------------------------- |
| `provisioning` | Agent, spec, planner en schema worden ingesteld                     |
| `active`       | Schema ingeschakeld; runs worden uitgevoerd op `schedule.frequency` |
| `paused`       | Schema uitgeschakeld via `/pause`                                   |
| `failed`       | Provisioning of schema update mislukt (`error_message` ingesteld)   |
| `deleted`      | Soft-verwijderd via `DELETE`                                        |

## Voorbeeld gebruiksscenario's

Hieronder staan veelvoorkomende monitorpatronen. Elk voorbeeld heeft alleen `query` en `frequency` nodig bij het aanmaken; voeg `notification` en `webhook` later toe als je meldingen wilt bij de eerste run of bij wijzigingen.

### Y Combinator nieuwe lanceringen

Houd [Y Combinator Launches](https://www.ycombinator.com/launches/) in de gaten voor nieuw gepubliceerde startups. Na planning is `tracked.type` `urls` en wijst `tracked.urls` naar de launches pagina.

<CodeGroup>
  ```python Python theme={null}
  import requests

  API_URL = "https://api.olostep.com/v1"
  headers = {
      "Authorization": "Bearer <YOUR_API_KEY>",
      "Content-Type": "application/json",
  }

  requests.post(
      f"{API_URL}/monitors",
      headers=headers,
      json={
          "query": "Stel me op de hoogte wanneer een nieuwe startup lanceert op Y Combinator Launches",
          "frequency": "elke 20 minuten",
      },
  )
  ```

  ```js Node theme={null}
  const API_URL = 'https://api.olostep.com/v1'

  await fetch(`${API_URL}/monitors`, {
    method: 'POST',
    headers: { 'Authorization': 'Bearer <YOUR_API_KEY>', 'Content-Type': 'application/json' },
    body: JSON.stringify({
      query: 'Stel me op de hoogte wanneer een nieuwe startup lanceert op Y Combinator Launches',
      frequency: 'elke 20 minuten',
    }),
  })
  ```

  ```bash cURL theme={null}
  curl -sS -X POST "https://api.olostep.com/v1/monitors" \
    -H "Authorization: Bearer $OLOSTEP_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "query": "Stel me op de hoogte wanneer een nieuwe startup lanceert op Y Combinator Launches",
      "frequency": "elke 20 minuten"
    }'
  ```
</CodeGroup>

Voeg e-mail en webhook levering toe nadat de monitor `active` is:

```bash theme={null}
curl -s -X POST "https://api.olostep.com/v1/monitors/monitor_biglavgvq3" \
  -H "Authorization: Bearer $OLOSTEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "notification": {
      "channels": [{ "type": "email", "target": "you@example.com" }]
    },
    "webhook": { "url": "https://webhook.site/your-unique-id" }
  }'
```

Met `channels` ingesteld en `events` weggelaten, stelt de API standaard `["changed", "first_snapshot"]` in zodat je wordt gewaarschuwd bij de baseline run en wanneer een wijziging wordt gedetecteerd.

### Concurrent blogposts (AirOps, Profound)

Monitor een concurrent blogindex voor nieuwe posts. De planner lost `tracked.urls` op naar de blog URL (bijvoorbeeld `https://www.airops.com/blog` of `https://www.tryprofound.com/blog`).

<CodeGroup>
  ```bash cURL AirOps theme={null}
  curl -sS -X POST "https://api.olostep.com/v1/monitors" \
    -H "Authorization: Bearer $OLOSTEP_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "query": "Houd de AirOps blog in de gaten voor nieuwe blogposts",
      "frequency": "elke uur"
    }'
  ```

  ```bash cURL Profound theme={null}
  curl -sS -X POST "https://api.olostep.com/v1/monitors" \
    -H "Authorization: Bearer $OLOSTEP_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "query": "Houd de Profound blog in de gaten voor nieuwe blogposts",
      "frequency": "elke 20 minuten"
    }'
  ```
</CodeGroup>

Na creatie ziet een monitor in deze familie er als volgt uit:

```json theme={null}
{
  "id": "monitor_588ck513zd",
  "object": "monitor",
  "query": "Houd de Profound blog in de gaten voor nieuwe blogposts",
  "tracked": {
    "type": "urls",
    "urls": ["https://www.tryprofound.com/blog"],
    "web_query": null
  },
  "schedule": {
    "frequency": "elke 20 minuten",
    "cron": "15/20 * * * ? *",
    "timezone": "UTC",
    "next_run_at": "2026-05-29T15:15:00.000Z"
  },
  "status": "active"
}
```

Gebruik `events: ["changed"]` op `notification` als je alleen meldingen wilt wanneer nieuwe posts verschijnen, niet bij de eerste baseline snapshot.

### Aandelenprijsdrempel (Tesla)

Monitor een gestructureerde gegevensbron wanneer de voorwaarde numeriek is in plaats van een paginaverschil. De planner stelt `tracked.type` in op `data_api` en laat `tracked.urls` leeg.

```bash theme={null}
curl -sS -X POST "https://api.olostep.com/v1/monitors" \
  -H "Authorization: Bearer $OLOSTEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "Stel me op de hoogte wanneer de Tesla aandelenprijs onder de 436$ zakt",
    "frequency": "elke 12 minuten"
  }'
```

```json theme={null}
{
  "id": "monitor_7609p3191t",
  "object": "monitor",
  "query": "Stel me op de hoogte wanneer de Tesla aandelenprijs onder de 436$ zakt",
  "tracked": {
    "type": "data_api",
    "urls": [],
    "web_query": null
  },
  "schedule": {
    "frequency": "elke 12 minuten",
    "cron": "2/12 * * * ? *",
    "timezone": "UTC",
    "next_run_at": "2026-05-29T15:02:00.000Z"
  },
  "status": "active"
}
```

### OpenAI API changelog

Ontvang meldingen wanneer [OpenAI’s API changelog](https://developers.openai.com/api/docs/changelog) nieuwe functies, modelreleases of afschrijvingen vermeldt. Noem de changelog URL in `query` of pin het met `source_policy.include_urls`.

```bash theme={null}
curl -sS -X POST "https://api.olostep.com/v1/monitors" \
  -H "Authorization: Bearer $OLOSTEP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "Stel me op de hoogte wanneer de OpenAI API changelog nieuwe updates of functies heeft https://developers.openai.com/api/docs/changelog",
    "frequency": "elke uur",
    "notification": {
      "events": ["changed"],
      "channels": [{ "type": "email", "target": "you@example.com" }]
    }
  }'
```

Stel `events` in op `["changed"]` zodat je wordt gewaarschuwd wanneer de changelog inhoud verandert, niet alleen wanneer de eerste snapshot is opgeslagen.

### Beheer van meerdere monitors

Lijst elke monitor voor je team om status, schema's en opgeloste doelen op één plek te zien:

```bash theme={null}
curl -s -X GET "https://api.olostep.com/v1/monitors" \
  -H "Authorization: Bearer $OLOSTEP_API_KEY"
```

Een team dat de bovenstaande voorbeelden uitvoert, kan verschillende monitors naast elkaar zien—blogwatches op verschillende ritmes, een `data_api` prijswacht, en een YC launches monitor met e-mail en webhook geconfigureerd—met `"count": 4` (of meer) in de respons.

## Veelvoorkomende validatiefouten

De monitor endpoints geven duidelijke validatiefouten terug voor veelvoorkomende ongeldige verzoeken:

* Ontbrekende of lege `query`
* `frequency` die geen plannings taal is, te vaak oplost (onder 10 minuten), of meer dan 50 tekens bevat
* Ongeldige `source_policy` vermeldingen (URL arrays moeten geldige `http`/`https` strings bevatten)
* Ongeldige `notification` vorm, onbekende `events`, of ongeldig kanaal `type` / `target`
* Ongeldige `webhook.url` (moet `http` of `https` zijn)
* Ongeldige `output_schema` (moet een geldige JSON Schema zijn)
* Ongeldige `monitor_id` of `run_id` formaat
* Update terwijl `status` `provisioning` is (`409`)
* Pauzeer/hervat wanneer status niet `active` / `paused` is

Voorbeeldfout:

```json theme={null}
{
  "error": "Kon 'frequency' niet interpreteren: \"check elke seconde\". Gebruik plannings taal zoals \"elke uur\" of \"elke dag om 9 uur\"."
}
```
