> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sixtyfour.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Monitor Endpoints

> Create monitors from rows or a file, read, update, trigger, and cancel them, and read a row's change history and table snapshots.

## Use case

Watch fields on a list of people or companies and read what changed. Use these endpoints to create a monitor from rows or from a file, inspect its rows and events, export the table at any point in time, and change or stop it. See [Monitors Overview](/api-reference/monitors/monitors-overview) for how checks work.

<Note>Monitors are available to organizations with Monitors enabled. Requests from other organizations return `403`.</Note>

<Card title="API Reference" icon="code" href="/api-reference/monitors/create-monitor">
  See the full request/response schema and parameters in the API Reference.
</Card>

## Pricing

After a row's first check, every tick bills a probe per active row. A full re-check at the monitor's tier is billed only when the probe finds a likely change. See [Credits & Pricing Guide](/guides/credits-and-pricing) for more information.

## Errors

For error responses (400, 403, 404, 409, etc.), see [Handling Errors](/api-reference/errors).

## Create monitor

Create one monitor from a table, with one row per subject.

```http theme={null}
POST https://api.sixtyfour.ai/monitors
```

| Field | Type | Required | Description |
| - | - | - | - |
| `name` | string | Yes | Monitor name, 1–120 characters. Each row is named after it, followed by the row's key values. |
| `rows` | array of objects | Yes | The table. At least one row. |
| `key_columns` | array of strings | Yes | Columns that identify each row. Every row needs a value in at least one of them. |
| `struct` | object | Yes | Watched fields: field name → description, or an object with `type`, `description`, and `subfields`. At least one field. A row column with the same name as a watched field sets that field's starting value. |
| `frequency` | string | No | How often to check, `1h` to `30d`. Default `1d`. |
| `tier` | string | No | Depth of the full re-check: `low` (default), `medium`, or `high`. |
| `subject_type` | string | No | `company` (default) or `lead`. |
| `research_plan` | string | No | Instructions for the enrichment that re-derives the fields. |
| `webhook_url` | string | No | Public URL that receives notifications. See [Monitor Notifications](/api-reference/monitors/monitor-notifications). |
| `webhook_event_types` | array of strings | No | Nonempty list of `monitor.field.changed`, `monitor.execution.completed`, `monitor.execution.failed`, or `monitor.run.completed`. Defaults to `["monitor.field.changed"]`. Duplicates are removed in first-occurrence order. |
| `metadata` | object | No | Free-form data stored on the monitor and echoed in events and notifications. |
| `is_active` | boolean | No | Default `true`. Set to `false` to create the monitor inactive: nothing is checked until you resume it with `POST /monitors/{monitor_id}/update` and `"is_active": true`. A monitor created inactive has `status: "paused"` and `disabled_reason: "paused"`. |
| `first_check` | string | No | `now` (default) immediately runs setup only for rows missing watched values. Complete rows wait for the schedule, including in mixed tables. `next_tick` defers every row to the first scheduled fire. |
| `idempotency_key` | string | No | Up to 200 characters. Resending the same request with the same key returns what the first attempt created. Keep the original settings when retrying, even if the monitor has since been updated. When omitted, the key is derived from the request body, so an identical resend also replays. |

Unknown request fields are rejected. The `struct` field uses the same name in monitor and row responses.

Creation is all or nothing. If any row is invalid, nothing is created. The response is `201` with the monitor, without its rows. Read them with [List rows](#list-rows).

### Example request

```json theme={null}
{
  "name": "Portfolio leadership",
  "key_columns": ["company_name", "domain"],
  "rows": [
    { "company_name": "Acme Robotics", "domain": "acmerobotics.com", "ceo_name": "Dana Lee" },
    { "company_name": "Northwind Labs", "domain": "northwindlabs.io" }
  ],
  "struct": {
    "ceo_name": "Full name of the current CEO",
    "headcount": { "type": "int", "description": "Current number of employees" }
  },
  "frequency": "1d",
  "tier": "low",
  "subject_type": "company",
  "webhook_url": "https://example.com/hooks/sixtyfour",
  "webhook_event_types": ["monitor.field.changed", "monitor.execution.completed", "monitor.execution.failed"],
  "metadata": { "portfolio_id": "p_42" }
}
```

### Example response

```json theme={null}
{
  "id": "0b7f2c6e-4a1d-4a8e-9f3b-2d5c8e1a7b90",
  "org_id": "org_abc123",
  "team_id": "5e1d9c3a-7b2f-4e6a-8c1d-3f9a2b4c6d8e",
  "name": "Portfolio leadership",
  "frequency": "1d",
  "struct": {
    "ceo_name": "Full name of the current CEO",
    "headcount": { "type": "int", "description": "Current number of employees" }
  },
  "tier": "low",
  "subject_type": "company",
  "research_plan": null,
  "is_active": true,
  "disabled_reason": null,
  "webhook_url": "https://example.com/hooks/sixtyfour",
  "webhook_event_types": ["monitor.field.changed", "monitor.execution.completed", "monitor.execution.failed"],
  "metadata": { "portfolio_id": "p_42" },
  "last_run_at": null,
  "next_run_times": [
    "2026-09-29T00:00:00+00:00",
    "2026-09-30T00:00:00+00:00",
    "2026-10-01T00:00:00+00:00"
  ],
  "row_count": 2,
  "active_row_count": 2,
  "status": "active",
  "created_at": "2026-09-28T17:05:12.482Z",
  "updated_at": "2026-09-28T17:05:12.482Z"
}
```

***

## Create monitor from a file

Create one monitor from an uploaded file, with one row per subject. Use this endpoint for large tables: the request returns as soon as the file is validated, and the rows are added afterwards.

```http theme={null}
POST https://api.sixtyfour.ai/monitors/upload
```

The request is `multipart/form-data` with two parts.

| Part | Type | Required | Description |
| - | - | - | - |
| `file` | file | Yes | A `.csv`, `.json`, `.jsonl`, or `.ndjson` file. Maximum 100 MB and 100,000 rows. CSV files need a header row. |
| `config` | string | Yes | The monitor's settings as a JSON-encoded string. Maximum 300,000 characters. |

`config` takes the same fields as [Create monitor](#create-monitor), except `rows` and `idempotency_key`: `name`, `key_columns`, `struct`, `frequency`, `tier`, `subject_type`, `research_plan`, `webhook_url`, `webhook_event_types`, `metadata`, `is_active`, and `first_check`. Unknown fields are rejected. Every column in `key_columns` must exist in the file.

| Header | Required | Description |
| - | - | - |
| `Idempotency-Key` | No | Up to 200 characters. Resending the same file and settings with the same key returns the monitor the first attempt created. When omitted, the key is derived from `config` and the file's contents, so resending the same file and settings also replays. |

The file is validated in full before anything is created. If any row is invalid, nothing is created.

The response is `202` with the monitor, without its rows. `status` is `starting` and `row_count` is `0`. Rows are then added in the background, in the file's order, and `row_count` rises as they arrive. When every row is in, `status` becomes `active`, `next_run_times` is populated, and setup runs only for incomplete rows if `first_check` is `now`. Complete rows wait for the schedule; `next_tick` defers all rows. Poll `GET /monitors/{monitor_id}` to follow progress.

While `status` is `starting`, no row is checked or billed. `POST /monitors/{monitor_id}/trigger` returns `409`, and so does `POST /monitors/{monitor_id}/update` when it changes `frequency` or `is_active`. `POST /monitors/{monitor_id}/cancel` is accepted: the rows finish adding and the monitor stays cancelled.

Uploads are limited to 10 per minute per organization. Replayed requests count toward the limit.

### Example request

```bash theme={null}
curl -X POST "https://api.sixtyfour.ai/monitors/upload" \
  -H "x-api-key: YOUR_API_KEY" \
  -F "file=@companies.csv" \
  -F 'config={
    "name": "Portfolio leadership",
    "key_columns": ["company_name", "domain"],
    "struct": {
      "ceo_name": "Full name of the current CEO",
      "headcount": {"type": "int", "description": "Current number of employees"}
    },
    "frequency": "1d",
    "tier": "low",
    "subject_type": "company"
  }'
```

### Example response

```json theme={null}
{
  "id": "0b7f2c6e-4a1d-4a8e-9f3b-2d5c8e1a7b90",
  "org_id": "org_abc123",
  "team_id": "5e1d9c3a-7b2f-4e6a-8c1d-3f9a2b4c6d8e",
  "name": "Portfolio leadership",
  "frequency": "1d",
  "struct": {
    "ceo_name": "Full name of the current CEO",
    "headcount": { "type": "int", "description": "Current number of employees" }
  },
  "tier": "low",
  "subject_type": "company",
  "research_plan": null,
  "is_active": true,
  "disabled_reason": "Rows are still being added.",
  "webhook_url": null,
  "metadata": null,
  "last_run_at": null,
  "next_run_times": [],
  "row_count": 0,
  "active_row_count": 0,
  "status": "starting",
  "created_at": "2026-09-28T17:05:12.482Z",
  "updated_at": "2026-09-28T17:05:12.482Z"
}
```

### Interrupted uploads

If adding rows fails, `status` becomes `failed` and `disabled_reason` explains the failure. Send the same request again to finish it: rows that were already added are kept, and only the missing rows are written.

A monitor that stays in `starting` with a `row_count` that has stopped rising was interrupted. Send the same request again once five minutes have passed since `updated_at`.

***

## List monitors

Retrieve your team's monitors, newest first. Rows are not included.

```http theme={null}
GET https://api.sixtyfour.ai/monitors
```

| Query parameter | Default | Description |
| - | - | - |
| `include_inactive` | `false` | Include inactive monitors. |
| `include_cancelled` | `true` | Include cancelled monitors when `include_inactive` is `true`. Set to `false` to exclude cancelled monitors while retaining active and paused monitors. |
| `limit` | `50` | Page size, 1–200. |
| `cursor` | — | `next_cursor` from the previous page. |

The response is `{ "monitors": [...], "next_cursor": "..." }`. `next_cursor` is `null` on the last page.

***

## Get monitor

Retrieve a monitor: its settings, `status`, and row counts. Rows are not included; read them with [List rows](#list-rows).

```http theme={null}
GET https://api.sixtyfour.ai/monitors/{monitor_id}
```

<Warning>This endpoint previously returned every row in a `rows` field. It now returns the monitor only. Read rows with `GET /monitors/{monitor_id}/rows`.</Warning>

Every monitor response includes `status`:

| `status` | Meaning |
| - | - |
| `starting` | Rows from an uploaded file are still being added. Nothing is checked yet. |
| `failed` | Adding rows from an uploaded file failed. Nothing is checked. Send the upload request again to finish it. |
| `active` | The monitor is checking its rows on schedule. |
| `paused` | Checks are paused and can be resumed. `is_active` is `false`; `disabled_reason` says why. |
| `cancelled` | Future checks are permanently stopped. The monitor cannot be resumed or updated. |

Paused and cancelled monitors return `next_run_times: []`.

***

## List rows

Retrieve a page of a monitor's rows, switched-off rows included, in the order they were added.

```http theme={null}
GET https://api.sixtyfour.ai/monitors/{monitor_id}/rows
```

| Query parameter | Default | Description |
| - | - | - |
| `limit` | `100` | Rows per page, 1–1000. |
| `cursor` | — | `next_cursor` from the previous page. |

The response is `{ "rows": [...], "next_cursor": "..." }`. `next_cursor` is `null` on the last page. To read the whole table at once as CSV, [download a snapshot](#download-snapshot) instead.

A row has no schedule of its own. Its `next_run_times` are the monitor's, and are empty when the row is switched off or the monitor is paused or cancelled.

### Example response

```json theme={null}
{
  "rows": [
    {
      "id": "8c3e1f2a-6b4d-4c9e-a1f7-2e5d9b3c7a10",
      "org_id": "org_abc123",
      "team_id": "5e1d9c3a-7b2f-4e6a-8c1d-3f9a2b4c6d8e",
      "name": "Portfolio leadership — Acme Robotics, acmerobotics.com",
      "frequency": "1d",
      "subject": { "company_name": "Acme Robotics", "domain": "acmerobotics.com" },
      "struct": {
        "ceo_name": "Full name of the current CEO",
        "headcount": { "type": "int", "description": "Current number of employees" }
      },
      "baseline": { "ceo_name": "Dana Lee" },
      "tier": "low",
      "subject_type": "company",
      "research_plan": null,
      "is_active": true,
      "disabled_reason": null,
      "webhook_url": "https://example.com/hooks/sixtyfour",
      "webhook_event_types": ["monitor.field.changed", "monitor.execution.completed", "monitor.execution.failed"],
      "metadata": { "portfolio_id": "p_42" },
      "last_run_at": null,
      "next_run_times": ["2026-09-29T00:00:00+00:00"],
      "created_at": "2026-09-28T17:05:12.531Z",
      "updated_at": "2026-09-28T17:05:12.531Z"
    }
  ],
  "next_cursor": null
}
```

***

## Get the monitor a workflow run started

Retrieve the monitor that a workflow's `monitor` block started. Read its rows with [List rows](#list-rows).

```http theme={null}
GET https://api.sixtyfour.ai/monitors/for-run/{workflow_run_id}/{block_id}
```

Returns `404` when that block did not start a monitor, or when the monitor belongs to another team. See the [`monitor` block](/api-reference/workflows/workflow-blocks#monitor).

***

## Update monitor

Change a monitor’s settings, including how often it runs, how deeply it researches, and where it notifies.

```http theme={null}
POST https://api.sixtyfour.ai/monitors/{monitor_id}/update
```

`struct` is fixed at creation. Changing watched fields requires a new monitor, with its own baseline and history.

All body fields are optional: `name`, `frequency`, `tier`, `webhook_url`, `webhook_event_types`, `metadata`, `is_active`. Changes apply to every row. Send `null` for `webhook_url` or `metadata` to clear them. Unknown fields are rejected. Cancelled monitors cannot be updated.

`webhook_event_types` replaces the subscription with a nonempty list of `monitor.field.changed`, `monitor.execution.completed`, `monitor.execution.failed`, or `monitor.run.completed`. Omit it to keep the current subscription, or send `null` to restore `["monitor.field.changed"]`. Duplicate names collapse in first-occurrence order. The monitor and all its rows return the effective subscription in `webhook_event_types`.

`is_active: false` pauses the whole monitor; `is_active: true` resumes a paused monitor. Pausing through this endpoint sets `disabled_reason: "paused"`, and resuming clears it. A row you switched off stays off when the monitor resumes.

### Example request

```json theme={null}
{
  "frequency": "6h",
  "tier": "medium",
  "webhook_event_types": ["monitor.field.changed", "monitor.execution.completed"]
}
```

***

## Trigger monitor

Check every active row now, without waiting for the next scheduled fire.

```http theme={null}
POST https://api.sixtyfour.ai/monitors/{monitor_id}/trigger
```

Returns `202` with `{ "status": "accepted", "monitor_id": "..." }`. Returns `409` if the monitor is not active, or its `status` is `starting` or `failed`. If a check of the monitor is already running, the triggered one is skipped.

***

## Cancel monitor

Permanently stop future checks for the whole monitor. Existing baselines and history remain readable. Cancellation cannot be undone; create a new monitor to start checks again. To stop checks temporarily, [pause the monitor](#update-monitor) instead.

```http theme={null}
POST https://api.sixtyfour.ai/monitors/{monitor_id}/cancel
```

Returns the monitor with `status: "cancelled"`, `is_active: false`, `disabled_reason: "cancelled"`, and `next_run_times: []`. Cancelling again returns the cancelled monitor.

***

## Get row

Retrieve one row, including the values its watched fields currently hold in `baseline`.

```http theme={null}
GET https://api.sixtyfour.ai/monitors/{monitor_id}/rows/{row_id}
```

***

## Switch a row on or off

Include or exclude one row from checks.

```http theme={null}
POST https://api.sixtyfour.ai/monitors/{monitor_id}/rows/{row_id}
Content-Type: application/json

{"is_active": false}
```

`is_active` is a required boolean in the JSON body. Send `true` to include the row again. Unknown body fields are rejected. Rows of a cancelled monitor cannot be changed. A switched-off row is skipped on every tick, is not billed, and keeps its baseline and history. Its `disabled_reason` is `excluded`.

***

## List row events

Retrieve one row's events, newest first.

```http theme={null}
GET https://api.sixtyfour.ai/monitors/{monitor_id}/rows/{row_id}/events
```

| Query parameter | Default | Description |
| - | - | - |
| `event_group_id` | — | Only the events from one check, for example the `event_group_id` from a notification. |
| `field` | — | Only one field's history. |
| `include_completions` | `false` | Include `completion` events for checks that found no change. |
| `limit` | `20` | 1–500. |

### Example response

```json theme={null}
[
  {
    "id": "e41c7a2b-9d3f-4b6e-8a1c-5f2d7e9b3a60",
    "event_group_id": "a7d2e9f1-3c5b-4e8a-9b1d-6f4c2e8a0b37",
    "event_type": "change",
    "field": "ceo_name",
    "previous_value": "Dana Lee",
    "current_value": "Priya Raman",
    "payload": {
      "sources": ["https://acmerobotics.com/about/leadership"],
      "confidence": 92,
      "justification": "The company's leadership page lists Priya Raman as CEO as of September 2026.",
      "hint": "Leadership page updated with a new CEO.",
      "metadata": { "portfolio_id": "p_42" }
    },
    "created_at": "2026-10-02T00:04:51.118Z"
  }
]
```

See [Events](/api-reference/monitors/monitors-overview#events) for every event type.

***

## List snapshots

List every moment the monitor's data changed, newest first, each with a download link. A snapshot is recorded per change, not per check: the changes from one tick share one snapshot.

```http theme={null}
GET https://api.sixtyfour.ai/monitors/{monitor_id}/snapshots
```

Optional query parameter: `limit` — 1–500, default `100`.

### Example response

```json theme={null}
[
  {
    "as_of": "2026-10-02T00:04:51+00:00",
    "changed_fields": ["ceo_name"],
    "subjects_changed": 1,
    "url": "https://api.sixtyfour.ai/monitors/0b7f2c6e-4a1d-4a8e-9f3b-2d5c8e1a7b90/snapshots/2026-10-02T00%3A04%3A51%2B00%3A00"
  }
]
```

***

## Download snapshot

Download the table as it stood at a moment, as CSV: one row per subject, with the key columns followed by the watched fields.

```http theme={null}
GET https://api.sixtyfour.ai/monitors/{monitor_id}/snapshots/{as_of}
```

`as_of` is an `as_of` value from the snapshot list, URL-encoded, or `latest` for the current values. Any ISO 8601 timestamp is accepted and returns the values held at that time.

***

## Example usage

### Create from a file

Upload a file, then wait until every row is added.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.sixtyfour.ai/monitors/upload" \
    -H "x-api-key: YOUR_API_KEY" \
    -F "file=@companies.csv" \
    -F 'config={"name": "Portfolio leadership", "key_columns": ["company_name", "domain"], "struct": {"ceo_name": "Full name of the current CEO"}, "frequency": "1d", "subject_type": "company"}'

  curl "https://api.sixtyfour.ai/monitors/MONITOR_ID" \
    -H "x-api-key: YOUR_API_KEY"
  ```

  ```python Python theme={null}
  import json
  import time

  import requests

  API_KEY = "YOUR_API_KEY"
  BASE_URL = "https://api.sixtyfour.ai"
  headers = {"x-api-key": API_KEY}

  config = {
      "name": "Portfolio leadership",
      "key_columns": ["company_name", "domain"],
      "struct": {"ceo_name": "Full name of the current CEO"},
      "frequency": "1d",
      "subject_type": "company",
  }

  with open("companies.csv", "rb") as f:
      response = requests.post(
          f"{BASE_URL}/monitors/upload",
          headers=headers,
          files={"file": ("companies.csv", f, "text/csv")},
          data={"config": json.dumps(config)},
      )
  response.raise_for_status()
  monitor = response.json()

  while monitor["status"] == "starting":
      time.sleep(5)
      poll = requests.get(f"{BASE_URL}/monitors/{monitor['id']}", headers=headers)
      poll.raise_for_status()
      monitor = poll.json()

  if monitor["status"] == "failed":
      raise RuntimeError(monitor["disabled_reason"])
  print(monitor["status"], monitor["row_count"])
  ```

  ```javascript JavaScript theme={null}
  import { readFile } from "node:fs/promises";

  const API_KEY = "YOUR_API_KEY";
  const BASE_URL = "https://api.sixtyfour.ai";
  const headers = { "x-api-key": API_KEY };

  const form = new FormData();
  form.append(
    "file",
    new Blob([await readFile("companies.csv")], { type: "text/csv" }),
    "companies.csv",
  );
  form.append(
    "config",
    JSON.stringify({
      name: "Portfolio leadership",
      key_columns: ["company_name", "domain"],
      struct: { ceo_name: "Full name of the current CEO" },
      frequency: "1d",
      subject_type: "company",
    }),
  );

  const response = await fetch(`${BASE_URL}/monitors/upload`, {
    method: "POST",
    headers,
    body: form,
  });
  if (!response.ok) {
    throw new Error(`Failed to create monitor: ${await response.text()}`);
  }
  let monitor = await response.json();

  while (monitor.status === "starting") {
    await new Promise((resolve) => setTimeout(resolve, 5000));
    const poll = await fetch(`${BASE_URL}/monitors/${monitor.id}`, { headers });
    if (!poll.ok) {
      throw new Error(`Failed to read monitor: ${await poll.text()}`);
    }
    monitor = await poll.json();
  }

  if (monitor.status === "failed") {
    throw new Error(monitor.disabled_reason);
  }
  console.log(monitor.status, monitor.row_count);
  ```
</CodeGroup>

### Create from rows

Create a monitor, then read the changes for one of its rows.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.sixtyfour.ai/monitors" \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Portfolio leadership",
      "key_columns": ["company_name", "domain"],
      "rows": [
        {"company_name": "Acme Robotics", "domain": "acmerobotics.com", "ceo_name": "Dana Lee"}
      ],
      "struct": {"ceo_name": "Full name of the current CEO"},
      "frequency": "1d",
      "subject_type": "company"
    }'

  curl "https://api.sixtyfour.ai/monitors/MONITOR_ID/rows" \
    -H "x-api-key: YOUR_API_KEY"

  curl "https://api.sixtyfour.ai/monitors/MONITOR_ID/rows/ROW_ID/events?field=ceo_name" \
    -H "x-api-key: YOUR_API_KEY"
  ```

  ```python Python theme={null}
  import requests

  API_KEY = "YOUR_API_KEY"
  BASE_URL = "https://api.sixtyfour.ai"
  headers = {"x-api-key": API_KEY, "Content-Type": "application/json"}

  response = requests.post(
      f"{BASE_URL}/monitors",
      headers=headers,
      json={
          "name": "Portfolio leadership",
          "key_columns": ["company_name", "domain"],
          "rows": [
              {"company_name": "Acme Robotics", "domain": "acmerobotics.com", "ceo_name": "Dana Lee"}
          ],
          "struct": {"ceo_name": "Full name of the current CEO"},
          "frequency": "1d",
          "subject_type": "company",
      },
  )
  response.raise_for_status()
  monitor = response.json()

  rows = requests.get(f"{BASE_URL}/monitors/{monitor['id']}/rows", headers=headers)
  rows.raise_for_status()
  row_id = rows.json()["rows"][0]["id"]

  events = requests.get(
      f"{BASE_URL}/monitors/{monitor['id']}/rows/{row_id}/events",
      headers=headers,
      params={"field": "ceo_name"},
  )
  events.raise_for_status()
  for event in events.json():
      print(event["event_type"], event["previous_value"], "->", event["current_value"])
  ```

  ```javascript JavaScript theme={null}
  const API_KEY = "YOUR_API_KEY";
  const BASE_URL = "https://api.sixtyfour.ai";
  const headers = { "x-api-key": API_KEY, "Content-Type": "application/json" };

  const response = await fetch(`${BASE_URL}/monitors`, {
    method: "POST",
    headers,
    body: JSON.stringify({
      name: "Portfolio leadership",
      key_columns: ["company_name", "domain"],
      rows: [
        { company_name: "Acme Robotics", domain: "acmerobotics.com", ceo_name: "Dana Lee" },
      ],
      struct: { ceo_name: "Full name of the current CEO" },
      frequency: "1d",
      subject_type: "company",
    }),
  });
  if (!response.ok) {
    throw new Error(`Failed to create monitor: ${await response.text()}`);
  }
  const monitor = await response.json();

  const rowsResponse = await fetch(`${BASE_URL}/monitors/${monitor.id}/rows`, {
    headers,
  });
  if (!rowsResponse.ok) {
    throw new Error(`Failed to read rows: ${await rowsResponse.text()}`);
  }
  const rowId = (await rowsResponse.json()).rows[0].id;

  const eventsResponse = await fetch(
    `${BASE_URL}/monitors/${monitor.id}/rows/${rowId}/events?field=ceo_name`,
    { headers },
  );
  const events = await eventsResponse.json();
  for (const event of events) {
    console.log(event.event_type, event.previous_value, "->", event.current_value);
  }
  ```
</CodeGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.