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

# Monitore

> Seiten nach einem Zeitplan überwachen und Änderungsbenachrichtigungen senden

Über den Olostep-Endpunkt `/v1/monitors` kannst du dauerhafte Monitore erstellen, die nach einem festen Zeitplan laufen, Seitenänderungen erkennen und dich per E-Mail, Slack, SMS oder einem dedizierten Webhook benachrichtigen.

* Erstelle einen Monitor aus einer natürlichen Sprach-`query`
* Begrenze Quellen mit `source_policy`
* Führe Überprüfungen nach Zeitplänen in natürlicher Sprache durch (mindestens alle 10 Minuten, UTC)
* Konfiguriere `notification.channels` und optionale `webhook`-Lieferung
* Streame den Bereitstellungsfortschritt mit Server-Sent Events (`?stream=1`)
* Liste, inspiziere, aktualisiere, pausiere, setze fort und lösche Monitore
* Lies Snapshot-Ereignisse, Planungsartefakte, Laufprotokolle und Live-Agentenprotokolle

Standardmäßig erfasst jeder Monitorlauf einen **vollständigen Snapshot** der überwachten Seite — ein vollständiges Bild ihres aktuellen Zustands zu diesem Zeitpunkt. Wenn du möchtest, dass der Monitor nur das Neue oder Geänderte zwischen den Läufen (Deltas) anzeigt, anstatt den vollständigen Zustand, drücke diese Absicht in der `query` aus.

## Installation

<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: integriertes curl ist ausreichend
  ```
</CodeGroup>

## Erstelle einen Monitor

Erstelle einen Monitor mit `POST /v1/monitors`. Die API validiert deine Eingaben, reserviert einen Monitor-Datensatz, stellt einen Schattenagenten bereit, generiert eine Workflow-Spezifikation, reiht die DAG-Planung ein und erstellt einen wiederkehrenden Zeitplan.

* `query` ist erforderlich — beschreibe, was in natürlicher Sprache überwacht werden soll.
* `frequency` ist optional und standardmäßig auf `jede Stunde` gesetzt. Verwende Planungsphrasen wie `jeden Tag um 9 Uhr` (Zeitpläne laufen in **UTC**; Mindestintervall ist **10 Minuten**).
* `source_policy` schränkt optional `include_urls`, `exclude_urls`, `include_domains` und `exclude_domains` ein.
* `notification` konfiguriert, wann und wie benachrichtigt werden soll (`events` + `channels`). Die Kanalzustellung wird zur Laufzeit durch die Monitor-Pipeline aufgelöst — du übergibst keine Empfänger an die DAG.
* `webhook` ist ein separates Objekt (`{ "url": "https://…" }`) für HTTP-Rückrufe zusätzlich zu `notification.channels`.
* `output_schema` erzwingt optional eine strukturierte Extraktion (gültiges JSON-Schema).

Die Erstellungsantwort ist HTTP `202` mit `status: provisioning`. Der Monitor wechselt zu `active`, nachdem die Planung `tracked`-Ziele aufgelöst hat. Poll `GET /v1/monitors/:monitor_id` oder übergebe `?stream=1` (oder `Accept: text/event-stream`), um die Bereitstellungsphasen und Spezifikationsbegründungstoken über SSE zu verfolgen.

### Beispielanfrage

Du benötigst nur `query` und `frequency`. Benachrichtigungskanäle und Webhooks können später mit `POST /v1/monitors/:monitor_id` hinzugefügt werden.

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

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

  payload = {
      "query": "Benachrichtige mich, wenn ein neues Startup auf Y Combinator Launches startet",
      "frequency": "alle 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: 'Benachrichtige mich, wenn ein neues Startup auf Y Combinator Launches startet',
      frequency: 'alle 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": "Benachrichtige mich, wenn ein neues Startup auf Y Combinator Launches startet",
      "frequency": "alle 20 Minuten"
    }'
  ```
</CodeGroup>

### Antwort

Eine erfolgreiche Erstellung (nicht-streaming) gibt HTTP `202` mit einem Monitor-Objekt zurück. `tracked` ist leer, bis die Planung abgeschlossen ist; poll `GET /v1/monitors/:monitor_id`, bis `status` `active` ist und `tracked.urls` gefüllt ist.

```json theme={null}
{
  "id": "monitor_biglavgvq3",
  "object": "monitor",
  "query": "Benachrichtige mich, wenn ein neues Startup auf Y Combinator Launches startet",
  "tracked": {
    "type": null,
    "urls": [],
    "web_query": null
  },
  "source_policy": {},
  "schedule": {
    "frequency": "alle 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
}
```

### Strukturierte Monitor-Ausgabe

Setze `output_schema`, wenn du möchtest, dass die Extraktionsergebnisse einer bestimmten JSON-Struktur folgen. Das Schema muss ein gültiges JSON-Schema sein.

### Bereitstellungsstream

Füge `?stream=1` hinzu oder sende `Accept: text/event-stream`, um SSE-Ereignisse zu erhalten, während der Monitor erstellt wird:

| Ereignis          | Beschreibung                                                          |
| ----------------- | --------------------------------------------------------------------- |
| `phase`           | Bereitstellungsschritt (`running`, `done` oder `failed`)              |
| `reasoning_token` | Inkrementeller Spezifikationsentwurfstext                             |
| `reasoning_reset` | Kürzt gepufferte Begründungen nach einem fehlgeschlagenen LLM-Versuch |
| `complete`        | Endgültiges Monitorobjekt (gleiche Form wie die `202`-Antwort)        |
| `error`           | Endgültiger Fehler                                                    |

## Benachrichtigungen und Webhooks

Benachrichtigungen werden im Monitor-Datensatz konfiguriert und zur Laufzeit aufgelöst — bette keine Kanalziele in die Überwachungs-`query` ein.

### `notification`

| Feld       | Beschreibung                                                                                                                                                                                                                             |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `events`   | Welche Lauf-Ergebnisse sollen die Zustellung auslösen. Siehe [Benachrichtigungsereignisse](#notification-events) unten. Wenn du `channels` setzt und `events` weglässt, ist der Standardwert sowohl `changed` als auch `first_snapshot`. |
| `channels` | Liste von `{ "type", "target", "events"? }` Objekten                                                                                                                                                                                     |

#### Benachrichtigungsereignisse

Verwende `events`, um anzugeben, **wann** du benachrichtigt werden möchtest. Erlaubte Werte:

| Ereignis         | Bedeutung                                                                                                                                                                                                            |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `changed`        | Benachrichtige, wenn der Monitor eine **Änderung** im Vergleich zum vorherigen Snapshot erkennt (zum Beispiel neuer Inhalt, aktualisierter Preis oder ein Unterschied, den die Pipeline als geändert klassifiziert). |
| `first_snapshot` | Benachrichtige, wenn der Monitor seinen **ersten Snapshot** erstellt — der erste Baseline-Lauf, der den aktuellen Inhalt speichert, bevor spätere Vergleiche durchgeführt werden.                                    |

Du kannst eines oder beide einschließen. Zum Beispiel, `["changed"]` benachrichtigt nur bei Updates nach der Baseline; `["first_snapshot"]` bestätigt die Einrichtung, ohne auf einen Unterschied zu warten; `["changed", "first_snapshot"]` deckt beides ab.

Pro-Kanal-`events` auf einem Kanalobjekt verwenden die gleichen Werte und überschreiben die Top-Level-Liste nur für diesen Kanal.

Unterstützte Kanaltypen:

| `type`  | `target` Format                                   |
| ------- | ------------------------------------------------- |
| `email` | Gültige E-Mail-Adresse                            |
| `slack` | Slack-Eingangs-Webhook-URL                        |
| `sms`   | E.164-Telefonnummer (zum Beispiel `+14155552671`) |

### `webhook`

Unabhängig von `notification.channels` empfängt `webhook.url` HTTP-POST-Nutzlasten, wenn der Monitor deine Callback-URL auslöst. Du kannst sowohl einen Webhook als auch Kanalbenachrichtigungen auf demselben Monitor verwenden.

### Beispiele

Nur E-Mail:

```json theme={null}
{
  "query": "Beobachte Änderungen auf https://example.com/terms",
  "frequency": "jeden Tag um 10 Uhr",
  "notification": {
    "events": ["changed"],
    "channels": [
      { "type": "email", "target": "legal@example.com" }
    ]
  }
}
```

Webhook-Callback:

```json theme={null}
{
  "query": "Beobachte Änderungen auf https://example.com/terms",
  "frequency": "jeden Tag um 10 Uhr",
  "webhook": {
    "url": "https://hooks.example.com/olostep-monitor"
  }
}
```

SMS:

```json theme={null}
{
  "query": "Benachrichtige mich, wenn https://status.example.com einen Vorfall anzeigt",
  "frequency": "jede Stunde",
  "notification": {
    "channels": [
      { "type": "sms", "target": "+14155552671" }
    ]
  }
}
```

## Quellenrichtlinie

Verwende `source_policy`, um einzuschränken, welche URLs und Domains der Planer verwenden darf.

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

## Frequenzen

Setze `frequency` in natürlicher Sprache, zum Beispiel:

* `jede Stunde` (Standard, wenn weggelassen)
* `jeden Tag um 9 Uhr`
* `jeden Wochentag um 14:30 Uhr`

Regeln:

* Muss als Planungssprache lesbar sein (keine willkürliche Monitorfrage).
* Mindestintervall: **alle 10 Minuten**.
* Zeitpläne werden in **UTC** gespeichert und ausgeführt (`schedule.timezone` ist `UTC`).
* Maximale Länge: 50 Zeichen.

Die API leitet einen Cron-Ausdruck aus deinem `frequency`-Text ab und zeigt ihn in `schedule.cron` an. Wenn der Monitor `active` ist, zeigt `schedule.next_run_at` den nächsten Lauf in ISO 8601 an.

## Monitore auflisten

Rufe alle Monitore für dein Team mit `GET /v1/monitors` ab.

Standardmäßig werden gelöschte Monitore herausgefiltert. Verwende `?include_deleted=true`, um sie einzuschließen.

<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"Gesamtanzahl Monitore: {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(`Gesamtanzahl Monitore: ${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>

### Antwortform

```json theme={null}
{
  "monitors": [
    {
      "id": "monitor_0wj35czpn7",
      "object": "monitor",
      "query": "Beobachte den AirOps-Blog für neue Blogbeiträge",
      "tracked": {
        "type": "urls",
        "urls": ["https://www.airops.com/blog"],
        "web_query": null
      },
      "source_policy": {},
      "schedule": {
        "frequency": "jede Stunde",
        "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": "Benachrichtige mich, wenn ein neues Startup auf Y Combinator Launches startet",
      "tracked": {
        "type": "urls",
        "urls": ["https://www.ycombinator.com/launches/"],
        "web_query": null
      },
      "source_policy": {},
      "schedule": {
        "frequency": "alle 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
}
```

## Einen Monitor abrufen

Rufe einen einzelnen Monitor mit `GET /v1/monitors/:monitor_id` ab.

Die Antwort enthält `last_run` (zusammenfassende Informationen des letzten Snapshots) und `total_count` (Anzahl der Snapshots), es sei denn, du übergibst `include_total_count=false`. Füge `include-diagram=true` hinzu, um ein `mermaid_diagram` des Monitor-DAGs einzuschließen.

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

### Antwortform

```json theme={null}
{
  "id": "monitor_biglavgvq3",
  "object": "monitor",
  "query": "Benachrichtige mich, wenn ein neues Startup auf Y Combinator Launches startet",
  "tracked": {
    "type": "urls",
    "urls": ["https://www.ycombinator.com/launches/"],
    "web_query": null
  },
  "source_policy": {},
  "schedule": {
    "frequency": "alle 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
}
```

## Monitor-Ereignisse auflisten

Verwende `GET /v1/monitors/:monitor_id/events`, um Snapshot-Ereignisse für einen Monitor aufzulisten.

Paginierung:

* `limit` (Standard `25`, max `100`)
* `cursor` (undurchsichtiger Token aus `next_cursor`)
* `count_only=true` gibt nur `{ "total_count": N }` zurück

Ereignisse werden in absteigender Reihenfolge zurückgegeben. Jedes Element enthält eine kurzlebige, vorab signierte `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>

### Antwortform

```json theme={null}
{
  "data": [
    {
      "id": "run_iwsoafcpyx",
      "run_id": "run_iwsoafcpyx",
      "created": 1780063395,
      "changed": false,
      "summary": "Erster Snapshot dieses Monitors wurde erstellt. Aktuellen Inhalt als Baseline gespeichert.",
      "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
}
```

## Monitor-Planung abrufen

Verwende `GET /v1/monitors/:monitor_id/planning`, um die FDA-Workflow-Spezifikation und den Planer-DAG nach der Bereitstellung zu inspizieren.

```json theme={null}
{
  "spec": {
    "saved_at": "2026-05-29T12:00:00.000000+00:00",
    "status": "complete",
    "goal": "Verfolge Preise auf 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": [] }
  }
}
```

## Einen Monitorlauf abrufen

Verwende `GET /v1/monitors/:monitor_id/runs/:run_id` für Snapshot-Metadaten und geparste Agentenprotokollereignisse für eine Ausführung (`run_id` muss mit `run_` beginnen).

```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": "Lauf run_v7k2p9m3 abgeschlossen. Dateien hochgeladen: 2",
      "event": { "type": "run_complete", "run_id": "run_v7k2p9m3", "files_uploaded": 2 }
    }
  ]
}
```

## Agentenprotokolle streamen

Verwende `GET /v1/monitors/:monitor_id/agent-logs?stream=1` (oder `Accept: text/event-stream`), um CloudWatch-Protokolle für den Agenten des Monitors zu verfolgen, gefiltert auf diese `monitor_id`.

Optionaler Abfrageparameter `since` ist ein Millisekunden-Zeitstempel (Standard: vor 30 Minuten).

SSE-Ereignistypen: `ready`, `log`, `heartbeat`, `error`.

## Einen Monitor aktualisieren

Aktualisiere einen Monitor mit `POST /v1/monitors/:monitor_id`.

Unterstützte Felder (nur das einfügen, was du ändern möchtest):

* `metadata` — wird mit vorhandenen Schlüsseln zusammengeführt; leere Zeichenfolgenwerte löschen Schlüssel
* `frequency` — erstellt den internen Zeitplan neu und setzt `status` zurück auf `active`
* `notification` — ersetzt das gesamte Benachrichtigungsobjekt
* `webhook` — `null` übergeben, um zu entfernen

Gibt `409` zurück, während `status` `provisioning` ist.

Wenn du `notification.channels` ohne `events` hinzufügst, setzt die API `events` standardmäßig auf `["changed", "first_snapshot"]`.

### E-Mail-Benachrichtigung hinzufügen

<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": "Benachrichtige mich, wenn ein neues Startup auf Y Combinator Launches startet",
  "tracked": {
    "type": "urls",
    "urls": ["https://www.ycombinator.com/launches/"],
    "web_query": null
  },
  "source_policy": {},
  "schedule": {
    "frequency": "alle 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
}
```

### Webhook hinzufügen

<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": "Benachrichtige mich, wenn ein neues Startup auf Y Combinator Launches startet",
  "tracked": {
    "type": "urls",
    "urls": ["https://www.ycombinator.com/launches/"],
    "web_query": null
  },
  "source_policy": {},
  "schedule": {
    "frequency": "alle 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
}
```

## Einen Monitor pausieren

Pausiere einen Monitor mit `POST /v1/monitors/:monitor_id/pause`.

Das Pausieren deaktiviert den zugrunde liegenden Zeitplan und setzt `status` auf `paused`. Nur Monitore mit `status: active` können pausiert werden. Der Anfragetext ist leer.

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

Bei Erfolg wird `200` mit dem Monitor und `status: paused` zurückgegeben. `schedule.next_run_at` ist `null`, während pausiert.

## Einen Monitor fortsetzen

Setze einen pausierten Monitor mit `POST /v1/monitors/:monitor_id/resume` fort.

Das Fortsetzen aktiviert den Zeitplan erneut und setzt `status` zurück auf `active`. Nur `paused`-Monitore können fortgesetzt werden.

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

## Einen Monitor löschen

Lösche einen Monitor mit `DELETE /v1/monitors/:monitor_id`.

Das Löschen löscht die Monitorzeile soft (`status: deleted`) und entfernt seine Zeitplan- und Schattenagenten-Ressourcen.

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

## Monitorstatus

| Status         | Bedeutung                                                                           |
| -------------- | ----------------------------------------------------------------------------------- |
| `provisioning` | Agent, Spezifikation, Planer und Zeitplan werden eingerichtet                       |
| `active`       | Zeitplan aktiviert; Läufe werden gemäß `schedule.frequency` ausgeführt              |
| `paused`       | Zeitplan über `/pause` deaktiviert                                                  |
| `failed`       | Bereitstellung oder Zeitplanaktualisierung fehlgeschlagen (`error_message` gesetzt) |
| `deleted`      | Soft-gelöscht über `DELETE`                                                         |

## Beispielanwendungsfälle

Nachfolgend sind gängige Monitor-Muster aufgeführt. Jedes Beispiel benötigt nur `query` und `frequency` zur Erstellungszeit; füge `notification` und `webhook` später hinzu, wenn du Benachrichtigungen beim ersten Lauf oder bei Änderungen möchtest.

### Neue Y Combinator-Starts

Beobachte [Y Combinator Launches](https://www.ycombinator.com/launches/) für neu veröffentlichte Startups. Nach der Planung ist `tracked.type` `urls` und `tracked.urls` zeigt auf die Launches-Seite.

<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": "Benachrichtige mich, wenn ein neues Startup auf Y Combinator Launches startet",
          "frequency": "alle 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: 'Benachrichtige mich, wenn ein neues Startup auf Y Combinator Launches startet',
      frequency: 'alle 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": "Benachrichtige mich, wenn ein neues Startup auf Y Combinator Launches startet",
      "frequency": "alle 20 Minuten"
    }'
  ```
</CodeGroup>

Füge E-Mail- und Webhook-Zustellung hinzu, nachdem der Monitor `active` ist:

```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" }
  }'
```

Mit `channels` gesetzt und `events` weggelassen, setzt die API standardmäßig `["changed", "first_snapshot"]`, sodass du beim Baseline-Lauf und bei jeder erkannten Änderung benachrichtigt wirst.

### Wettbewerber-Blogbeiträge (AirOps, Profound)

Überwache einen Wettbewerber-Blog-Index auf neue Beiträge. Der Planer löst `tracked.urls` zur Blog-URL auf (zum Beispiel `https://www.airops.com/blog` oder `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": "Beobachte den AirOps-Blog für neue Blogbeiträge",
      "frequency": "jede Stunde"
    }'
  ```

  ```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": "Beobachte den Profound-Blog für neue Blogbeiträge",
      "frequency": "alle 20 Minuten"
    }'
  ```
</CodeGroup>

Nach der Erstellung sieht ein Monitor in dieser Familie so aus:

```json theme={null}
{
  "id": "monitor_588ck513zd",
  "object": "monitor",
  "query": "Beobachte den Profound-Blog für neue Blogbeiträge",
  "tracked": {
    "type": "urls",
    "urls": ["https://www.tryprofound.com/blog"],
    "web_query": null
  },
  "schedule": {
    "frequency": "alle 20 Minuten",
    "cron": "15/20 * * * ? *",
    "timezone": "UTC",
    "next_run_at": "2026-05-29T15:15:00.000Z"
  },
  "status": "active"
}
```

Verwende `events: ["changed"]` auf `notification`, wenn du nur Benachrichtigungen möchtest, wenn neue Beiträge erscheinen, nicht beim ersten Baseline-Snapshot.

### Aktienkurs-Schwelle (Tesla)

Überwache eine strukturierte Datenquelle, wenn die Bedingung numerisch ist und nicht ein Seitenunterschied. Der Planer setzt `tracked.type` auf `data_api` und lässt `tracked.urls` leer.

```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": "Benachrichtige mich, wenn der Tesla-Aktienkurs unter 436$ fällt",
    "frequency": "alle 12 Minuten"
  }'
```

```json theme={null}
{
  "id": "monitor_7609p3191t",
  "object": "monitor",
  "query": "Benachrichtige mich, wenn der Tesla-Aktienkurs unter 436$ fällt",
  "tracked": {
    "type": "data_api",
    "urls": [],
    "web_query": null
  },
  "schedule": {
    "frequency": "alle 12 Minuten",
    "cron": "2/12 * * * ? *",
    "timezone": "UTC",
    "next_run_at": "2026-05-29T15:02:00.000Z"
  },
  "status": "active"
}
```

### OpenAI API-Änderungsprotokoll

Lass dich benachrichtigen, wenn das [OpenAI API-Änderungsprotokoll](https://developers.openai.com/api/docs/changelog) neue Funktionen, Modellveröffentlichungen oder Abkündigungen auflistet. Erwähne die Änderungsprotokoll-URL in `query` oder fixiere sie mit `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": "Benachrichtige mich, wenn das OpenAI API-Änderungsprotokoll neue Updates oder Funktionen hat https://developers.openai.com/api/docs/changelog",
    "frequency": "jede Stunde",
    "notification": {
      "events": ["changed"],
      "channels": [{ "type": "email", "target": "you@example.com" }]
    }
  }'
```

Setze `events` auf `["changed"]`, damit du benachrichtigt wirst, wenn sich der Inhalt des Änderungsprotokolls ändert, nicht nur, wenn der erste Snapshot gespeichert wird.

### Verwaltung mehrerer Monitore

Liste jeden Monitor für dein Team auf, um Status, Zeitpläne und aufgelöste Ziele an einem Ort zu sehen:

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

Ein Team, das die oben genannten Beispiele ausführt, könnte mehrere Monitore nebeneinander sehen — Blogüberwachungen mit unterschiedlichen Frequenzen, eine `data_api`-Preisüberwachung und einen YC-Launches-Monitor mit konfigurierter E-Mail- und Webhook-Benachrichtigung — mit `"count": 4` (oder mehr) in der Antwort.

## Häufige Validierungsfehler

Die Monitor-Endpunkte geben klare Validierungsfehler für häufige ungültige Anfragen zurück:

* Fehlende oder leere `query`
* `frequency`, die keine Planungssprache ist, zu oft auflöst (unter 10 Minuten) oder 50 Zeichen überschreitet
* Ungültige `source_policy`-Einträge (URL-Arrays müssen gültige `http`/`https`-Zeichenfolgen enthalten)
* Ungültige `notification`-Form, unbekannte `events` oder ungültiger Kanal-`type` / `target`
* Ungültige `webhook.url` (muss `http` oder `https` sein)
* Ungültiges `output_schema` (muss gültiges JSON-Schema sein)
* Ungültiges `monitor_id` oder `run_id`-Format
* Aktualisierung, während `status` `provisioning` ist (`409`)
* Pause/fortsetzen, wenn der Status nicht `active` / `paused` ist

Beispiel für einen Fehler:

```json theme={null}
{
  "error": "Konnte 'frequency' nicht interpretieren: \"jede Sekunde prüfen\". Verwende Planungssprache wie \"jede Stunde\" oder \"jeden Tag um 9 Uhr\"."
}
```
