Skip to content
Signal
Dashboard

Runs

Run kinds, statuses, progress, results, credits, polling and cancellation.

A run is one asynchronous job: discovery, import, monitor or export. A start operation returns 202 with a run in the status queued. The work continues after the response. Read the run with get_run until it has a final status. A queued or running status does not mean that the work is complete.

Runs can start paid research

Discovery runs and import runs start paid research and use credits. The scheduled runs of a monitor and of a campaign discovery also use credits. Export runs use no credits. Do not start a paid run to test a client: use read operations for tests.

The run object

FieldTypeDescription
idUUIDRequired. ID of the run.
kindenumRequired. discovery, import, monitor or export. See Run kinds.
campaign_idUUIDNullable. ID of the campaign of the run.
monitor_idUUIDNullable. ID of the monitor of a monitor run. Null for the other kinds.
statusenumRequired. See Run statuses.
skipped_reasonstringNullable. Why a skipped run did not start, for example insufficient_credits. Null when the status is not skipped.
triggerenumRequired. scheduled when a schedule started the run, else manual.
created_attimestampRequired. Time when the run was created.
started_attimestampNullable. Time when the run started to work. Null when it is not known.
finished_attimestampNullable. Time when the run finished. Null while the run is not finished, and while a canceled run stops.
progressobjectNullable. The queue counts. See Progress and result. Null before the queue starts, and after the queue data expires at 30 days.
resultobjectNullable. The result of a finished run. Null while the run is not finished, for a skipped run, and when the counts are not known.
error_codeenumNullable. Stable reason code of a failed, canceled or skipped run. See Error codes. Null for a run that is queued, running or succeeded.
errorstringNullable. Error text of a failed, canceled or skipped run, for a person. The text can change: do not parse it. Use error_code in your code.
{
  "id": "6d7e8f9a-0b1c-4d2e-9f3a-4b5c6d7e8f9a",
  "kind": "export",
  "campaign_id": "3f2b8a4e-1c5d-4e7f-9a0b-6c2d8e1f4a7b",
  "monitor_id": null,
  "status": "succeeded",
  "skipped_reason": null,
  "trigger": "manual",
  "created_at": "2026-09-23T12:00:00.000Z",
  "started_at": "2026-09-23T12:00:00.000Z",
  "finished_at": "2026-09-23T12:00:09.000Z",
  "progress": {
    "target": 120,
    "queued": 0,
    "completed": 120,
    "discarded": 0
  },
  "result": {
    "completed": 120,
    "discarded": null,
    "download_url": "https://example.com/exports/accounts.csv",
    "download_expires_at": "2026-09-23T13:00:09.000Z"
  },
  "error_code": null,
  "error": null
}

Run kinds

KindStarted byUses creditsresult.completed
discoverystart_discovery, or the discovery schedule of a campaignYesAccounts that the run added. The count does not include the people of the accounts.
importstart_import (JSON rows) or upload_import (CSV file)YesRows that the run added.
monitorThe schedule of a monitor, or run_monitorYesSignals that the run processed.
exportstart_exportNoAccounts or people in the file.

Credits

Signal charges credits for each action that a run takes, not for each run. These are the prices:

ActionCredits
Create an account or a person1
Update an account or a person with research data1
Find the phone number of a person0.5 for each phone number
Create a signal1
Send one monitor search query0.1

A monitor sends one search query for each watched record and each signal type in its config.

ExampleEstimate
start_discovery with count 25 and contacts_per_account 2Up to 25 accounts and 50 people: 75 credits to create them, plus 1 credit for each research update.
start_import with 100 rows1 credit for each record that the import creates, plus 1 credit for each research update.
A monitor run that watches 200 accounts for 2 signal types400 queries: 40 credits, plus 1 credit for each signal that the run creates.
start_export0 credits.

Send get_me to read the balance before you start a run. Signal also checks the balance while a run works, and stops the run when the credits run out. A start with no credits gives 402. Read Start rules.

Run statuses

A run has one of six statuses. succeeded, failed, canceled and skipped are final.

StatusDescription
queuedThe run waits to start. Every start operation returns this status.
runningThe run does its work.
succeededThe run finished. result holds the counts.
failedThe run stopped with an error. error_code and error give the reason.
canceledThe run was canceled with cancel_run, delete_monitor or delete_campaign, or Signal stopped a stuck run.
skippedA scheduled run that did not start because the organization had no credits. skipped_reason is insufficient_credits.

Signal stops a discovery, import or monitor run that stays queued for 2 hours after its start time, or that shows no activity for 2 hours. The run then gets the status canceled, or succeeded when it produced output. A canceled run keeps the records that it added before the cancel.

Diagram

Cancellation keeps completed records and the credits already used. While cancellation stops the worker, finished_at can remain null. Deleting a campaign or monitor removes API access to its run history. See Cancel rules.

Error codes

error_code is a stable value. Use it in your code.

error_codeStatusMeaning
insufficient_creditsskippedThe organization had no credits when the scheduled run was due.
canceled_by_usercanceledA request canceled the run: cancel_run, delete_monitor or delete_campaign.
canceled_stuckcanceledSignal stopped the run because it did not start, or showed no activity, for 2 hours.
worker_crashedfailedThe worker that ran the run stopped. Start the run again.
run_failedfailedThe run stopped with an error.

Progress and result

progress holds the queue counts while the run works:

FieldDescription
targetNumber of items that the run put in its queue.
queuedNumber of items that wait in the queue.
completedNumber of items that the run finished.
discardedNumber of items that the run rejected. A monitor run has none.

result holds the final counts of a finished run. The fields that apply depend on the kind:

FieldTypeDescription
completedintegerNullable. The meaning depends on the kind. See Run kinds.
discardedintegerNullable. Discovery and import: items that the run rejected. Null for the other kinds.
download_urlstringNullable. Export: URL of the CSV file. Null for the other kinds.
download_expires_attimestampNullable. Export: time when download_url stops working.

Start rules

A start returns 202 with a queued run. Each job reference owns its request and result rules:

A paid start with no credits gives 402 and starts no run. See Errors.

Cancel rules

  • cancel_run cancels a run that is queued or running. The run gets the status canceled.
  • A run that is already finished gives 409.
  • An export run cannot be canceled. cancel_run on an export run gives 409.
  • After cancel_run, finished_at stays null until the run stops. Read the run again with get_run to get the end time.
  • delete_monitor cancels the active runs of the monitor. delete_campaign cancels active runs of discovery and import configurations that it removes. Independent monitors continue.
  • Explicit monitor deletion makes its runs unreadable. Source campaign deletion retains monitors and their runs.

Export download

See the Export reference.

List and poll

list_runs lists the runs of the organization, newest first. It takes the filters campaign_id, kind, status, created_after (at or after) and created_before (before). The time filters are RFC 3339 strings. The list shows the stored status. get_run gives the current status of one run.

Poll get_run every 15 seconds, for at most 240 attempts (60 minutes). If the run stays active, send cancel_run when supported and contact support with its ID. Stop when the status is final. The campaign field active_run_ids lists the discovery, import and monitor runs that are queued or running.

Operations

Each path below follows $LINKT_API_URL/v2. Set LINKT_API_URL to the origin only, for example https://api.signal.linkt.ai.

OperationMethod and pathPurpose
list_runsGET /runsList the runs of the organization, newest first.
get_runGET /runs/{run_id}Get one run with its current status, progress and result.
cancel_runPOST /runs/{run_id}/cancelCancel a queued or running run.
start_discoveryPOST /runs/discoveryStart a discovery run. Uses credits.
start_importPOST /runs/importImport accounts or people from JSON rows. Uses credits.
upload_importPOST /runs/import/uploadImport accounts or people from a CSV file. Uses credits.
start_exportPOST /runs/exportExport accounts or people to a CSV file. Uses no credits.
curl --fail-with-body --request GET "$LINKT_API_URL/v2/runs/$RUN_ID" \
  --header "x-api-key: $LINKT_API_KEY"

API reference: get_run

curl --fail-with-body --request GET "$LINKT_API_URL/v2/runs?limit=5" \
  --header "x-api-key: $LINKT_API_KEY"

API reference: list_runs

Correlate import rows

POST /v2/runs/import accepts 1 to 1,000 JSON rows. Import research and qualification use the campaign criteria. Each row has a zero-based index. Optional external_id keeps your original string, including leading zeroes. Duplicate and empty external IDs are valid. Use row_index to distinguish repeated rows.

{
  "campaign_id": "01950000-0000-7000-8000-000000000001",
  "entity_type": "person",
  "rows": [
    {
      "first_name": "Ada",
      "last_name": "Lovelace",
      "email": "ada@example.com",
      "external_id": "001",
      "account_id": "01950000-0000-7000-8000-000000000002"
    }
  ]
}

Accounts accept name, website, domain, and linkedin_url. People also accept first_name, last_name, email, and title. Extra fields remain research input. linkedin_url maps to the stored LinkedIn field. external_id never affects identity matching. Server-owned fields such as row_index, signal_id, and parent_id do not set internal context.

A person can name an existing account with account_id. The account must belong to your organization. Signal adds an account copy to the campaign when needed and keeps that account as the person's parent during research. A missing, foreign, deleted, or unavailable account produces account_not_found.

Missing names, invalid field types, malformed CSV, and invalid file envelopes return 422 before a run starts. These requests have no row outcomes. Research, qualification, account lookup, and persistence failures after admission produce row outcomes.

Retrieve outcomes

Read GET /v2/runs/{run_id} until result.import_rows.availability is ready. Then call list_import_rows with GET /v2/runs/{run_id}/rows?limit=25. Pages contain at most 100 rows, in ascending row_index order. Send next_cursor to retrieve the next page. A cursor belongs to one run and one organization.

{
  "data": [
    {
      "row_index": 0,
      "external_id": "001",
      "entity_type": "person",
      "status": "matched",
      "signal_id": "01950000-0000-7000-8000-000000000003",
      "reason_code": null
    }
  ],
  "next_cursor": null
}
curl --fail-with-body --request GET "$LINKT_API_URL/v2/runs/$RUN_ID/rows?limit=5" \
  --header "x-api-key: $LINKT_API_KEY"

API reference: list_import_rows

created means the row creates a public identity. matched means the row resolves to an existing public identity. Both return signal_id. Identity matching uses the current name and secondary-identifier rules across campaigns. A repeated row can match an identity created by an earlier row. Additional researched records cannot replace the input record's result. Conflicting input candidates produce ambiguous_input_entity.

rejected returns signal_id: null and a stable reason_code:

CodeCondition
account_not_foundThe explicit account cannot supply a scoped campaign copy.
account_mismatchThe saved person's parent does not resolve to the explicit account.
not_qualifiedThe analyst rejects the row before saving its input record.
ambiguous_input_entityMultiple saved candidates correspond to the input.
processing_failedProcessing produces no recoverable input record.
credits_exhaustedCredits stop processing before the row is processed.
run_canceledThe worker stops after cancellation before processing the row.
run_failedThe worker fails before processing the row.

A saved copy whose identity is temporarily unresolved keeps outcomes pending for recovery. GET /rows returns 409 import_rows_pending while the import runs or outcomes are incomplete. A cancellation flag alone does not finalize rows. Failed and canceled imports retain saved successes after worker termination is confirmed. Retries recover saved copies and preserve final outcomes. Row outcomes survive queue expiry.

Historical imports have availability: "unavailable". Their row endpoint returns 409 import_rows_unavailable. Signal does not invent historical row mappings. A run of another kind returns 422 not_import_run. Final import counts come from row outcomes: completed equals created plus matched; discarded equals rejected.

On this page