Skip to main content
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 or across a date range, and change or stop it. See Monitors Overview for how checks work.
Monitors require access for your organization. Contact support@sixtyfour.ai.

API Reference

See the full request/response schema and parameters in the API Reference.
LinkedIn-specific field discovery and single-profile creation are documented in LinkedIn Monitors. The read, update, trigger, cancel, history, and export endpoints here apply to both monitor types.

Create monitor

Create one monitor from a table, with one row per subject.
Send exactly one of rows or handle_id; a monitor needs at least one row. For large tables, use Create monitor from a file. See Billing for what creation checks. 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.

Example request

Example response

Rows from an upload handle

handle_id reads the rows of a .csv, .json, .jsonl, or .ndjson file uploaded with POST /storage/csv/upload. The upload must belong to the same team as the request, and the file can hold up to 100,000 rows. The file is read when the monitor is created, and its rows pass the same checks as rows. With monitor_type: "linkedin", the file needs exactly one column of profile URLs, under any header. The response is still 201, but with status: "starting": rows are added in the background, as in Create monitor from a file.

Metadata

metadata is stored on the monitor and its rows. It is echoed in the payload of change and established events and in every notification. Sixtyfour adds keys that record where the rows came from: Your own keys sit beside them. Updating metadata replaces the whole object, including these keys.

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.
The request is multipart/form-data with two parts. config takes the fields of Create monitor except rows, handle_id, and idempotency_key. Every column in key_columns must exist in the file. 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 the first check follows first_check. Poll GET /monitors/{monitor_id} to follow progress. While status is starting, no row is checked or billed. The monitor cannot be triggered, and an update cannot change its frequency or is_active. POST /monitors/{monitor_id}/cancel is accepted: the rows finish adding and the monitor stays cancelled. Uploads are rate limited; see Rate Limits.

Example request

Example response

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. If status stays starting and updated_at is more than five minutes old, send the same request again.

List monitors

Retrieve your team’s monitors, newest first. Rows are not included.
The response is { "monitors": [...], "next_cursor": "..." }. A page can hold fewer than limit monitors, or none, before the last page. Keep requesting pages until next_cursor is null. URL-encode next_cursor when you send it back.

Get monitor

Retrieve a monitor: its settings, status, and row counts. Rows are not included; read them with List rows.
Every monitor response includes status: Paused and cancelled monitors return next_run_times: [].

Disabled reasons

disabled_reason says why a monitor or one of its rows is not being checked. It is null while checks run. A monitor created with is_active: false whose rows were added in the background has status: "paused" and disabled_reason: null. Rows paused with key_revoked, owner_removed, team_removed, or team_archived pause again at their next check if switched back on. Pausing a monitor does not change its rows’ disabled_reason.

List rows

Retrieve a page of a monitor’s rows, switched-off rows included, in the order they were added.
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 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


List monitor runs

List a monitor’s runs, newest first. A run is one scheduled or triggered check of the monitor, not a workflow run.
status is running, completed, or failed. Counts are final once status is completed or failed. rows_checked includes successful checks with no changes. A completed run can include failed row checks, reported in rows_failed. A run is failed when any row’s check ends in an error before recording a result, or the run stops before every row finishes. A failed run sends no monitor.run.completed notification, and its changed rows are not available from Get a run’s changed rows. The other rows’ changes are still recorded: read them from row events, List latest changes, or snapshots. Poll this list to catch runs that end without a notification. Both run endpoints accept limit (default 100, maximum 500) and cursor. Pass the response’s next_cursor unchanged as the next request’s cursor; null means there are no more pages.

Get a run’s changed rows

Retrieve only the rows changed by a completed run, with previous and current values for each changed field. Initial values and unchanged rows are excluded; a completed run with no changes returns changes: [].
Each entry contains all changed fields for that row.

List latest changes

Retrieve, for every row, when each watched field last changed. Use it to highlight recently changed cells without reading every row’s events.
The response maps row ID → field name → timestamp (ISO 8601, UTC) of that field’s latest change event. Only change events count; established values and checks that found nothing are excluded. Rows and fields that never changed are omitted, so a monitor with no changes returns {}. For the values themselves, list the row’s events or download a snapshot.

Get the monitor a workflow run started

Retrieve the monitor that a workflow’s monitor block started. Read its rows with List rows.
Only the monitor’s team can read it. See the monitor block.

List a workflow run’s monitors

Retrieve every monitor started from one workflow run, newest first. Rows are not included.
The response is a JSON array of up to 50 monitors. LinkedIn monitors are listed only when your organization has LinkedIn monitoring. For the next page, set cursor to {created_at}|{id} of the last monitor on the page, URL-encoded, with its time zone. An empty array ends the list.

Update monitor

Change a monitor’s settings, including how often it runs, how deeply it researches, and where it notifies.
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. Changing tier checks tier access and the team’s spend limit. For LinkedIn monitors, see Update a LinkedIn monitor. webhook_event_types replaces the subscription. Omit it to keep the current one, or send null to restore ["monitor.field.changed"]. 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


Trigger monitor

Check every active row now, without waiting for the next scheduled fire.
Returns 202 with { "status": "accepted", "monitor_id": "..." }. Only a monitor whose status is active can be triggered. If a check of the monitor is already running, the triggered one is skipped, with the same response. A triggered check runs every active row through the same steps as a scheduled check and is billed the same way. See Credit Costs.

Cancel monitor

Permanently stop future checks for the whole monitor. Existing baselines and history remain readable. Cancellation cannot be undone. To start checks again, create a new monitor with a new idempotency key. To stop checks temporarily, pause the monitor instead.
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.

Switch a row on or off

Include or exclude one row from checks.
is_active is a required boolean in the JSON body. Send true to include the row again. 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.
There is no cursor: a request returns at most the newest 500 events that match its filters. Narrow it with field or event_group_id, or read older values from snapshots or Export history.

Example response

See 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 for each second in which a value was established or changed, so one run of a large monitor records many snapshots.

Example response


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.
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. Cells hold the stored values unchanged, including any a spreadsheet would run as a formula.

Export history

Download many snapshots at once as a ZIP of CSVs, one file per snapshot. Each file has the same columns as Download snapshot and is named after its timestamp, with : replaced by -.
Send the snapshot selection in the JSON body. CSV cells hold the stored values unchanged, as in Download snapshot. Timestamps without a time zone are read as UTC. An export is limited to 5,000 snapshots and 50 MiB of CSV. A larger export, one that takes too long to build, or a range with no snapshots is refused before any data is sent; select fewer snapshots or a shorter range. Exports are rate limited; see Rate Limits. On 429 or 503, wait for Retry-After and send the request again, as the examples do.

Example usage

Create from a file

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

Create from rows

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

Create a LinkedIn monitor from multiple profiles

POST /monitors accepts multiple profiles with monitor_type: "linkedin", subject_type: "lead", and key_columns: ["linkedin_url"]. Each row contains only a LinkedIn person URL. The struct keys are selected field keys from discovery. There is one monitor ID and one schedule for the table.
Frequency, upload, and duplicate-profile rules for LinkedIn monitors are in LinkedIn Monitors.

Pricing

See Credit Costs for more information.

Errors

For error responses (400, 403, 404, 409, etc.), see Handling Errors.