Monitors
The monitor object: config types, frequency, status and the webhook URL.
A monitor looks for signals on a schedule. The V2 API creates organization-owned monitors through POST /monitors or the compatible campaign-nested route. Its config says what to watch and which signal types to look for. Each scheduled run of a monitor is a run of kind monitor, and the run can create signals. To move a V1 integration, read Migrate from V1.
A source campaign is required only for signal-sheet. A topic monitor needs no source campaign or existing records. Monitor targets and signal subjects explains independent monitors and retained signals in this candidate.
The monitor object
| Field | Type | Description |
|---|---|---|
id | UUID | Required. ID of the monitor. |
campaign_id | UUID | Nullable. ID of the campaign of the monitor. Null for an independent monitor. |
name | string | Required. Name of the monitor, 1 to 200 characters. |
config | object | Nullable. What the monitor looks for. See Config types. Null for an older monitor whose config the V2 API cannot read. |
frequency | enum | Nullable. daily, weekly or monthly. Null when the frequency is not known. |
status | enum | Required. active or paused. |
next_run_at | timestamp | Nullable. Time of the next scheduled run. Null when the monitor is paused. |
Config types
config.type selects what the monitor watches. The type cannot change after create.
| Type | Watches | Fields of the type |
|---|---|---|
signal-topic | A topic. It needs no records. | topic_criteria (required): the topic in natural language. geographic_filters, industry_filters, company_size_filters: nullable arrays of strings. Null means all. |
signal-sheet | The accounts or people of a campaign. | source_campaign_id (required): the campaign to watch. It can be the campaign of the monitor. Its account type must match entity_type; watching people needs entity_type: person and a campaign that targets people. An empty source is valid when it supports the requested record type. entity_filters (nullable): conditions on the records. |
signal-csv | The companies or people of an uploaded CSV file. | file_id (required): ID of the file, 24 hexadecimal characters. primary_column: the column with the record names. Default name. |
The V2 API cannot create the file_id of a signal-csv monitor. To watch the records of a CSV file, import the file with upload_import, then create a signal-sheet monitor for the campaign.
Every config type also has these fields:
| Field | Type | Description |
|---|---|---|
type | enum | Required. signal-topic, signal-sheet or signal-csv. |
signal_types | array | Required. The signal types to look for. Each item has type (a signal type), display (a display name) and description (the events to find). Use other for a custom type. |
entity_type | enum | The type of the monitored records: company, person, school_district, job_board or product. Default company. |
webhook_url | string | Nullable. See Webhook URL. |
entity_filters limits the records that a signal-sheet monitor watches. Null watches every record.
- Each key is
statusor the path of a data field, for exampledata.industry.value.statusmatches the stored review state. A record with no stored state readsnew. To match new records, send{"status": {"$in": ["new", null]}}. Older records can storecontacted, which the V2 API shows asreviewed. To match every record that readsreviewed, send{"status": {"$in": ["reviewed", "contacted"]}}. - Each value is a JSON scalar, which the field must equal, or an object of operators.
$eq,$ne,$gt,$gte,$ltand$ltetake a scalar.$inand$nintake a list of scalars.$existstakestrueorfalse.$regextakes a pattern of at most 200 characters. Start the pattern with(?i)to ignore case.- Other fields, other operators and top-level operators such as
$oror$wheregive 422.
Frequency and status
| Field | Values | Rule |
|---|---|---|
frequency | daily, weekly, monthly | Default weekly. The schedule starts from the time of the create_monitor call. A new frequency starts a new schedule cycle from the time of the update_monitor call. A monthly schedule made on day 29, 30 or 31 skips the months that do not have that day. Read next_run_at. |
status | active, paused | Default active. active lets the schedule start runs. paused starts no run. A monitor without a schedule is paused. |
- When the monitor is
active, the first run starts atnext_run_at. A paused monitor has a nullnext_run_at.create_monitordoes not start a run at once.run_monitorstarts one run now. The schedule does not change. - Each run of a monitor has
kindmonitorand themonitor_idof the monitor.result.completedis the number of signals that the run processed. Read Runs. - A scheduled run needs credits. A run that cannot start for lack of credits gets the status
skipped. - Send
statuspausedto stop the scheduled runs. Sendactiveto start them again.
Webhook URL
config.webhook_url is a URL that gets a notification when a run of the monitor ends. config.format selects the payload: legacy (the default) or v2. This section describes the legacy format. V2 webhooks describes the signed v2 format and its verification secret. There is no event subscription. Discovery, import and export runs have no webhook setting in the V2 API.
| Behavior | Value |
|---|---|
| Method | POST with a JSON body. |
| Body | An object with event_type, timestamp (UTC) and data. event_type is, for example, run.signal.completed, run.signal.failed, run.signal.cancelled or run.signal.crashed. The V2 API reference does not define the fields of data. |
| URL rules | The URL must use HTTPS. Signal does not send to localhost, 127.0.0.1 or ::1. The API accepts any string. Signal sends no notification to a URL that breaks these rules. |
| Timeout | 30 seconds for each attempt. |
| Retries | Up to 5 retries after a 5xx response, a timeout or a connection error. The delays are 2, 4, 8, 16 and 32 seconds. A 4xx response gets no retry. |
| Signature | None. A legacy request has no signature header. |
| Failure | A failed notification does not change the run. |
Signal routes a notification to the currently configured webhook of the monitor that started the run. Signal skips delivery when it cannot confirm that monitor. Notification payload IDs are not guaranteed to be V2 IDs.
Treat the notification as a prompt to read data through the API. Call get_run or list_runs for the run status. To read the new signals of a run, call list_signals with the monitor_id of the run and created_after set to the started_at of the run.
To set or clear the URL, send config.webhook_url to update_monitor. Send null to clear it.
Roles and changes
Monitor operations use resource permissions. Organization roles do not replace them. See Permissions.
-
Reading needs
monitor.read. Listing monitors through a campaign also needscampaign.read. -
Creation needs
monitor.writeandschedule.write. An active schedule also needsrun.write. Campaign-linked creation needs campaign access, and each source needs its own reads. -
Updating needs
monitor.write. Changing frequency or status also needsschedule.write, pluscampaign.writefor a campaign-linked monitor. Enabling recurring execution needsrun.write. -
Setting or clearing the webhook URL needs
webhook.write. -
run_monitorneedsmonitor.read,run.write, and the permissions of its execution inputs and effects. -
Deletion needs
monitor.writeandschedule.write. Canceling queued or running work also needsrun.write. -
update_monitorchanges only the fields in the body. A config change must use fields of the current config type. -
update_monitorgives 409 when you sendconfigfor a monitor with a nullconfig. It also gives 409 when you sendstatusactivefor a monitor with a nullcampaign_idand no schedule. -
delete_monitordeletes the monitor, its schedule and the signals that it found. It cancels the active runs of the monitor. After the delete,get_runandlist_runsdo not find the runs of the monitor. You cannot undo the delete.
Operations
Each path below follows $LINKT_API_URL/v2. Set LINKT_API_URL to the origin only, for example https://api.signal.linkt.ai.
| Operation | Method and path | Purpose |
|---|---|---|
list_monitors | GET /campaigns/{campaign_id}/monitors | List the monitors of a campaign. |
create_organization_monitor | POST /monitors | Create a monitor without campaign provenance. Returns 201. |
create_monitor | POST /campaigns/{campaign_id}/monitors | Create a monitor. Returns 201. |
get_monitor | GET /monitors/{monitor_id} | Get one monitor. |
update_monitor | PATCH /monitors/{monitor_id} | Change the name, config, frequency or status. |
delete_monitor | DELETE /monitors/{monitor_id} | Delete a monitor and its signals. Returns 204. |
run_monitor | POST /monitors/{monitor_id}/runs | Start one run of the monitor now. Returns 202. Uses credits. |
The next example creates a paused monitor. A paused monitor starts no run and uses no credits. Send status active to start the schedule. Each scheduled run uses credits.
curl --fail-with-body --request POST "$LINKT_API_URL/v2/campaigns/$CAMPAIGN_ID/monitors" \
--header "x-api-key: $LINKT_API_KEY" \
--header "Content-Type: application/json" \
--data "$(jq -cn --arg CAMPAIGN_ID "$CAMPAIGN_ID" '{"config":{"signal_types":[{"description":"A new funding round or a new investment.","display":"Funding","type":"funding"},{"description":"A new executive in data, IT, or engineering.","display":"Leadership change","type":"leadership_change"}],"source_campaign_id":"0190a4e2-0000-7000-8000-000000000001","type":"signal-sheet"},"frequency":"weekly","name":"Funding and leadership changes","status":"paused"} | walk(if . == "0190a4e2-0000-7000-8000-000000000001" then $CAMPAIGN_ID else . end)')"curl --fail-with-body --request GET "$LINKT_API_URL/v2/campaigns/$CAMPAIGN_ID/monitors?limit=5" \
--header "x-api-key: $LINKT_API_KEY"Related
Monitor create and update reject unknown fields inside each signal_types item with 422 validation_error. Each item accepts type, display and description. The validation details identify the unknown field with extra_forbidden.