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

# Monitor

> Monitora le pagine a intervalli programmati e invia avvisi di modifica

Attraverso l'endpoint Olostep `/v1/monitors` puoi creare monitor persistenti che funzionano su un programma fisso, rilevano le modifiche delle pagine e ti notificano tramite email, Slack, SMS o un webhook dedicato.

* Crea un monitor da una `query` in linguaggio naturale
* Limita le fonti con `source_policy`
* Esegui controlli su programmi in linguaggio naturale (minimo ogni 10 minuti, UTC)
* Configura `notification.channels` e consegna opzionale tramite `webhook`
* Trasmetti il progresso del provisioning con Server-Sent Events (`?stream=1`)
* Elenca, ispeziona, aggiorna, metti in pausa, riprendi ed elimina i monitor
* Leggi eventi snapshot, artefatti di pianificazione, log di esecuzione e log degli agenti in tempo reale

Per impostazione predefinita, ogni esecuzione del monitor cattura un **snapshot completo** della pagina monitorata — un'immagine completa del suo stato attuale in quel momento. Se vuoi che il monitor mostri solo ciò che è nuovo o cambiato tra le esecuzioni (delta) invece dello stato completo, esprimi questa intenzione nella `query`.

## Installazione

<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: il curl integrato va bene
  ```
</CodeGroup>

## Crea un monitor

Crea un monitor con `POST /v1/monitors`. L'API convalida il tuo input, riserva un record del monitor, fornisce un agente ombra, genera una specifica del flusso di lavoro, mette in coda la pianificazione del DAG e crea un programma ricorrente.

* `query` è obbligatoria — descrivi cosa monitorare in linguaggio naturale.
* `frequency` è opzionale e predefinita a `ogni ora`. Usa frasi di pianificazione come `ogni giorno alle 9am` (i programmi vengono eseguiti in **UTC**; l'intervallo minimo è **10 minuti**).
* `source_policy` limita facoltativamente `include_urls`, `exclude_urls`, `include_domains` e `exclude_domains`.
* `notification` configura quando e come avvisare (`events` + `channels`). La consegna del canale viene risolta in fase di esecuzione dalla pipeline del monitor — non passi i destinatari nel DAG.
* `webhook` è un oggetto separato (`{ "url": "https://…" }`) per le chiamate HTTP oltre a `notification.channels`.
* `output_schema` impone facoltativamente un'estrazione strutturata (JSON Schema valido).

La risposta alla creazione è HTTP `202` con `status: provisioning`. Il monitor passa a `active` dopo che la pianificazione risolve i target `tracked`. Effettua il polling con `GET /v1/monitors/:monitor_id` o passa `?stream=1` (o `Accept: text/event-stream`) per seguire le fasi di provisioning e i token di ragionamento delle specifiche tramite SSE.

### Esempio di richiesta

Hai bisogno solo di `query` e `frequency`. I canali di notifica e i webhook possono essere aggiunti successivamente con `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": "Notificami quando una nuova startup viene lanciata su Y Combinator Launches",
      "frequency": "ogni 20 minuti",
  }

  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: 'Notificami quando una nuova startup viene lanciata su Y Combinator Launches',
      frequency: 'ogni 20 minuti',
    }),
  })

  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": "Notificami quando una nuova startup viene lanciata su Y Combinator Launches",
      "frequency": "ogni 20 minuti"
    }'
  ```
</CodeGroup>

### Risposta

La creazione avvenuta con successo (non in streaming) restituisce HTTP `202` con un oggetto monitor. `tracked` è vuoto fino al termine della pianificazione; effettua il polling con `GET /v1/monitors/:monitor_id` fino a quando `status` è `active` e `tracked.urls` è popolato.

```json theme={null}
{
  "id": "monitor_biglavgvq3",
  "object": "monitor",
  "query": "Notificami quando una nuova startup viene lanciata su Y Combinator Launches",
  "tracked": {
    "type": null,
    "urls": [],
    "web_query": null
  },
  "source_policy": {},
  "schedule": {
    "frequency": "ogni 20 minuti",
    "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
}
```

### Output strutturato del monitor

Imposta `output_schema` quando vuoi che i risultati dell'estrazione seguano una struttura JSON specifica. Lo schema deve essere un JSON Schema valido.

### Stream di provisioning

Aggiungi `?stream=1` o invia `Accept: text/event-stream` per ricevere eventi SSE mentre il monitor viene creato:

| Evento            | Descrizione                                                       |
| ----------------- | ----------------------------------------------------------------- |
| `phase`           | Fase di provisioning (`running`, `done`, o `failed`)              |
| `reasoning_token` | Testo incrementale di progettazione delle specifiche              |
| `reasoning_reset` | Trunca il ragionamento bufferizzato dopo un tentativo LLM fallito |
| `complete`        | Oggetto monitor finale (stessa forma della risposta `202`)        |
| `error`           | Fallimento terminale                                              |

## Notifiche e webhook

Gli avvisi sono configurati sul record del monitor e risolti in fase di esecuzione — non incorporare i target dei canali nella `query` di monitoraggio.

### `notification`

| Campo      | Descrizione                                                                                                                                                                                                           |
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `events`   | Quali esiti delle esecuzioni devono attivare la consegna. Vedi [eventi di notifica](#notification-events) sotto. Se imposti `channels` e ometti `events`, il valore predefinito è sia `changed` che `first_snapshot`. |
| `channels` | Elenco di oggetti `{ "type", "target", "events"? }`                                                                                                                                                                   |

#### Eventi di notifica

Usa `events` per indicare **quando** vuoi essere notificato. Valori consentiti:

| Evento           | Significato                                                                                                                                                                                        |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `changed`        | Notifica quando il monitor rileva un **cambiamento** rispetto allo snapshot precedente (ad esempio nuovo contenuto, prezzo aggiornato, o una differenza che la pipeline classifica come cambiata). |
| `first_snapshot` | Notifica quando il monitor effettua il suo **primo snapshot** — l'esecuzione iniziale di base che memorizza il contenuto corrente prima dei confronti successivi.                                  |

Puoi includere uno o entrambi. Ad esempio, `["changed"]` avvisa solo sugli aggiornamenti dopo la base; `["first_snapshot"]` conferma l'impostazione senza aspettare una differenza; `["changed", "first_snapshot"]` copre entrambi.

Gli `events` per canale su un oggetto canale utilizzano gli stessi valori e sovrascrivono l'elenco a livello superiore solo per quel canale.

Tipi di canale supportati:

| `type`  | Formato `target`                                     |
| ------- | ---------------------------------------------------- |
| `email` | Indirizzo email valido                               |
| `slack` | URL webhook in entrata di Slack                      |
| `sms`   | Numero di telefono E.164 (ad esempio `+14155552671`) |

### `webhook`

Separato da `notification.channels`, `webhook.url` riceve payload HTTP POST quando il monitor attiva il tuo URL di callback. Puoi usare sia un webhook che le notifiche di canale sullo stesso monitor.

### Esempi

Solo email:

```json theme={null}
{
  "query": "Osserva le modifiche su https://example.com/terms",
  "frequency": "ogni giorno alle 10am",
  "notification": {
    "events": ["changed"],
    "channels": [
      { "type": "email", "target": "legal@example.com" }
    ]
  }
}
```

Callback webhook:

```json theme={null}
{
  "query": "Osserva le modifiche su https://example.com/terms",
  "frequency": "ogni giorno alle 10am",
  "webhook": {
    "url": "https://hooks.example.com/olostep-monitor"
  }
}
```

SMS:

```json theme={null}
{
  "query": "Avvisami quando https://status.example.com mostra un incidente",
  "frequency": "ogni ora",
  "notification": {
    "channels": [
      { "type": "sms", "target": "+14155552671" }
    ]
  }
}
```

## Politica delle fonti

Usa `source_policy` per limitare quali URL e domini il pianificatore può utilizzare.

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

## Frequenze

Imposta `frequency` in linguaggio naturale, ad esempio:

* `ogni ora` (predefinito se omesso)
* `ogni giorno alle 9am`
* `ogni giorno feriale alle 14:30`

Regole:

* Deve essere leggibile come linguaggio di pianificazione (non una domanda arbitraria del monitor).
* Intervallo minimo: **ogni 10 minuti**.
* I programmi sono memorizzati ed eseguiti in **UTC** (`schedule.timezone` è `UTC`).
* Lunghezza massima: 50 caratteri.

L'API deriva un'espressione cron dal tuo testo `frequency` e la espone su `schedule.cron`. Quando il monitor è `active`, `schedule.next_run_at` mostra la prossima esecuzione in ISO 8601.

## Elenca i monitor

Recupera tutti i monitor per il tuo team con `GET /v1/monitors`.

Per impostazione predefinita, i monitor eliminati sono filtrati. Usa `?include_deleted=true` per includerli.

<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"Total 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(`Total 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>

### Forma della risposta

```json theme={null}
{
  "monitors": [
    {
      "id": "monitor_0wj35czpn7",
      "object": "monitor",
      "query": "Osserva il blog di AirOps per nuovi post",
      "tracked": {
        "type": "urls",
        "urls": ["https://www.airops.com/blog"],
        "web_query": null
      },
      "source_policy": {},
      "schedule": {
        "frequency": "ogni ora",
        "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": "Notificami quando una nuova startup viene lanciata su Y Combinator Launches",
      "tracked": {
        "type": "urls",
        "urls": ["https://www.ycombinator.com/launches/"],
        "web_query": null
      },
      "source_policy": {},
      "schedule": {
        "frequency": "ogni 20 minuti",
        "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
}
```

## Ottieni un monitor

Recupera un singolo monitor con `GET /v1/monitors/:monitor_id`.

La risposta include `last_run` (riepilogo dell'ultimo snapshot) e `total_count` (conteggio degli snapshot) a meno che tu non passi `include_total_count=false`. Aggiungi `include-diagram=true` per includere un `mermaid_diagram` del DAG del monitor.

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

### Forma della risposta

```json theme={null}
{
  "id": "monitor_biglavgvq3",
  "object": "monitor",
  "query": "Notificami quando una nuova startup viene lanciata su Y Combinator Launches",
  "tracked": {
    "type": "urls",
    "urls": ["https://www.ycombinator.com/launches/"],
    "web_query": null
  },
  "source_policy": {},
  "schedule": {
    "frequency": "ogni 20 minuti",
    "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
}
```

## Elenca gli eventi del monitor

Usa `GET /v1/monitors/:monitor_id/events` per elencare gli eventi snapshot per un monitor.

Paginazione:

* `limit` (predefinito `25`, massimo `100`)
* `cursor` (token opaco da `next_cursor`)
* `count_only=true` restituisce solo `{ "total_count": N }`

Gli eventi sono restituiti dal più recente. Ogni elemento include un `snapshot_url` pre-firmato a breve termine.

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

### Forma della risposta

```json theme={null}
{
  "data": [
    {
      "id": "run_iwsoafcpyx",
      "run_id": "run_iwsoafcpyx",
      "created": 1780063395,
      "changed": false,
      "summary": "È stato effettuato il primo snapshot di questo monitor. Contenuto corrente memorizzato come base.",
      "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
}
```

## Ottieni la pianificazione del monitor

Usa `GET /v1/monitors/:monitor_id/planning` per ispezionare la specifica del flusso di lavoro FDA e il DAG del pianificatore dopo il provisioning.

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

## Ottieni un'esecuzione del monitor

Usa `GET /v1/monitors/:monitor_id/runs/:run_id` per i metadati dello snapshot e gli eventi di log dell'agente analizzati per un'esecuzione (`run_id` deve iniziare con `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": "Esecuzione run_v7k2p9m3 completata. File caricati: 2",
      "event": { "type": "run_complete", "run_id": "run_v7k2p9m3", "files_uploaded": 2 }
    }
  ]
}
```

## Stream dei log dell'agente

Usa `GET /v1/monitors/:monitor_id/agent-logs?stream=1` (o `Accept: text/event-stream`) per seguire i log di CloudWatch per l'agente del monitor, filtrati per questo `monitor_id`.

Il parametro di query opzionale `since` è un timestamp in millisecondi (predefinito: 30 minuti fa).

Tipi di eventi SSE: `ready`, `log`, `heartbeat`, `error`.

## Aggiorna un monitor

Aggiorna un monitor con `POST /v1/monitors/:monitor_id`.

Campi supportati (includi solo ciò che vuoi cambiare):

* `metadata` — unito con le chiavi esistenti; i valori di stringa vuoti eliminano le chiavi
* `frequency` — ricrea il programma interno e imposta `status` di nuovo su `active`
* `notification` — sostituisce l'intero oggetto di notifica
* `webhook` — passa `null` per rimuovere

Restituisce `409` mentre `status` è `provisioning`.

Quando aggiungi `notification.channels` senza `events`, l'API predefinisce `events` a `["changed", "first_snapshot"]`.

### Aggiungi notifica email

<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": "Notificami quando una nuova startup viene lanciata su Y Combinator Launches",
  "tracked": {
    "type": "urls",
    "urls": ["https://www.ycombinator.com/launches/"],
    "web_query": null
  },
  "source_policy": {},
  "schedule": {
    "frequency": "ogni 20 minuti",
    "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
}
```

### Aggiungi webhook

<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": "Notificami quando una nuova startup viene lanciata su Y Combinator Launches",
  "tracked": {
    "type": "urls",
    "urls": ["https://www.ycombinator.com/launches/"],
    "web_query": null
  },
  "source_policy": {},
  "schedule": {
    "frequency": "ogni 20 minuti",
    "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
}
```

## Metti in pausa un monitor

Metti in pausa un monitor con `POST /v1/monitors/:monitor_id/pause`.

Mettere in pausa disabilita il programma sottostante e imposta `status` su `paused`. Solo i monitor con `status: active` possono essere messi in pausa. Il corpo della richiesta è vuoto.

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

In caso di successo, restituisce `200` con il monitor e `status: paused`. `schedule.next_run_at` è `null` mentre è in pausa.

## Riprendi un monitor

Riprendi un monitor in pausa con `POST /v1/monitors/:monitor_id/resume`.

Riprendere riabilita il programma e imposta `status` di nuovo su `active`. Solo i monitor `paused` possono essere ripresi.

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

## Elimina un monitor

Elimina un monitor con `DELETE /v1/monitors/:monitor_id`.

L'eliminazione elimina in modo soft la riga del monitor (`status: deleted`) e rimuove le sue risorse di programma e agente ombra.

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

## Stato del monitor

| Stato          | Significato                                                                            |
| -------------- | -------------------------------------------------------------------------------------- |
| `provisioning` | L'agente, la specifica, il pianificatore e il programma sono in fase di configurazione |
| `active`       | Programma abilitato; le esecuzioni avvengono su `schedule.frequency`                   |
| `paused`       | Programma disabilitato tramite `/pause`                                                |
| `failed`       | Il provisioning o l'aggiornamento del programma è fallito (`error_message` impostato)  |
| `deleted`      | Eliminato in modo soft tramite `DELETE`                                                |

## Esempi di casi d'uso

Di seguito sono riportati i modelli comuni di monitor. Ogni esempio ha bisogno solo di `query` e `frequency` al momento della creazione; aggiungi `notification` e `webhook` in seguito se vuoi avvisi alla prima esecuzione o su modifiche.

### Nuovi lanci di Y Combinator

Osserva [Y Combinator Launches](https://www.ycombinator.com/launches/) per le startup pubblicate di recente. Dopo la pianificazione, `tracked.type` è `urls` e `tracked.urls` punta alla pagina dei lanci.

<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": "Notificami quando una nuova startup viene lanciata su Y Combinator Launches",
          "frequency": "ogni 20 minuti",
      },
  )
  ```

  ```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: 'Notificami quando una nuova startup viene lanciata su Y Combinator Launches',
      frequency: 'ogni 20 minuti',
    }),
  })
  ```

  ```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": "Notificami quando una nuova startup viene lanciata su Y Combinator Launches",
      "frequency": "ogni 20 minuti"
    }'
  ```
</CodeGroup>

Aggiungi la consegna via email e webhook dopo che il monitor è `active`:

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

Con `channels` impostato e `events` omesso, l'API predefinisce `["changed", "first_snapshot"]` così sei notificato sull'esecuzione di base e ogni volta che viene rilevata una modifica.

### Post del blog dei concorrenti (AirOps, Profound)

Monitora l'indice del blog di un concorrente per nuovi post. Il pianificatore risolve `tracked.urls` all'URL del blog (ad esempio `https://www.airops.com/blog` o `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": "Osserva il blog di AirOps per nuovi post",
      "frequency": "ogni ora"
    }'
  ```

  ```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": "Osserva il blog di Profound per nuovi post",
      "frequency": "ogni 20 minuti"
    }'
  ```
</CodeGroup>

Dopo la creazione, un monitor di questa famiglia appare così:

```json theme={null}
{
  "id": "monitor_588ck513zd",
  "object": "monitor",
  "query": "Osserva il blog di Profound per nuovi post",
  "tracked": {
    "type": "urls",
    "urls": ["https://www.tryprofound.com/blog"],
    "web_query": null
  },
  "schedule": {
    "frequency": "ogni 20 minuti",
    "cron": "15/20 * * * ? *",
    "timezone": "UTC",
    "next_run_at": "2026-05-29T15:15:00.000Z"
  },
  "status": "active"
}
```

Usa `events: ["changed"]` su `notification` se vuoi avvisi solo quando appaiono nuovi post, non sul primo snapshot di base.

### Soglia del prezzo delle azioni (Tesla)

Monitora una fonte di dati strutturata quando la condizione è numerica piuttosto che una differenza di pagina. Il pianificatore imposta `tracked.type` su `data_api` e lascia `tracked.urls` vuoto.

```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": "Notificami quando il prezzo delle azioni Tesla scende sotto i 436$",
    "frequency": "ogni 12 minuti"
  }'
```

```json theme={null}
{
  "id": "monitor_7609p3191t",
  "object": "monitor",
  "query": "Notificami quando il prezzo delle azioni Tesla scende sotto i 436$",
  "tracked": {
    "type": "data_api",
    "urls": [],
    "web_query": null
  },
  "schedule": {
    "frequency": "ogni 12 minuti",
    "cron": "2/12 * * * ? *",
    "timezone": "UTC",
    "next_run_at": "2026-05-29T15:02:00.000Z"
  },
  "status": "active"
}
```

### Changelog dell'API OpenAI

Ricevi notifiche quando il [changelog dell'API di OpenAI](https://developers.openai.com/api/docs/changelog) elenca nuove funzionalità, rilasci di modelli o deprecazioni. Menziona l'URL del changelog nella `query` o fissalo con `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": "Notificami quando il changelog dell'API di OpenAI ha nuovi aggiornamenti o funzionalità https://developers.openai.com/api/docs/changelog",
    "frequency": "ogni ora",
    "notification": {
      "events": ["changed"],
      "channels": [{ "type": "email", "target": "you@example.com" }]
    }
  }'
```

Imposta `events` su `["changed"]` in modo da essere avvisato quando il contenuto del changelog cambia, non solo quando viene memorizzato il primo snapshot.

### Gestione di più monitor

Elenca ogni monitor per il tuo team per vedere lo stato, i programmi e i target risolti in un unico posto:

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

Un team che esegue gli esempi sopra potrebbe vedere diversi monitor affiancati — osservazioni del blog su diverse cadenze, un controllo del prezzo `data_api` e un monitor di lanci YC con email e webhook configurati — con `"count": 4` (o più) nella risposta.

## Errori di convalida comuni

Gli endpoint del monitor restituiscono errori di convalida chiari per richieste non valide comuni:

* `query` mancante o vuota
* `frequency` che non è linguaggio di pianificazione, risolve troppo spesso (sotto i 10 minuti), o supera i 50 caratteri
* Voci `source_policy` non valide (gli array di URL devono contenere stringhe `http`/`https` valide)
* Forma `notification` non valida, `events` sconosciuti, o `type` / `target` del canale non valido
* `webhook.url` non valido (deve essere `http` o `https`)
* `output_schema` non valido (deve essere un JSON Schema valido)
* Formato `monitor_id` o `run_id` non valido
* Aggiornamento mentre `status` è `provisioning` (`409`)
* Pausa/ripresa quando lo stato non è `active` / `paused`

Esempio di errore:

```json theme={null}
{
  "error": "Impossibile interpretare 'frequency': \"controlla ogni secondo\". Usa il linguaggio di pianificazione come \"ogni ora\" o \"ogni giorno alle 9am\"."
}
```
