Get a watch run summary
Returns one run in full: its counts, its per-stage activity log, and every delivery attempt with
the records it carried under notifications[].payload.notifications[]. That is the same record
shape your channel receives, so a watch is readable here even when no channel is configured.
A watch whose config.payload_delivery_type is link serves its records from a file instead.
The response then carries a top-level payload_delivery block with a fresh link, and each
notifications[] entry keeps its outcome and drops payload. Reading a run hands you the same
file the run delivered, so the bytes match what your channel received; a watch with no channels
never pushed one, so the first read writes it.
Records are returned only for a run whose status is SUCCESS. A run can leave rows behind
without ever paying for or delivering them, and those rows must not be readable. The run itself,
with its status, counts, and logs, is still returned so you can see what happened.
Authorizations
API key passed as a Bearer token in the Authorization header.
Headers
API version to use. 2025-11-01 is the only accepted value. Send it on every call: it is
enforced today on POST /watch/{dataset}/search, where a missing or unrecognized value returns
400, and the other watch routes accept a request without it rather than relying on that.
2025-11-01 "2025-11-01"
Path Parameters
The dataset the watch is built on.
person, company, job, social_post "person"
The watch's id, returned when it was created.
46936
The run's id, from runs[].id on the run-history endpoint.
54811
Response
The run, its logs, and its deliveries.
One run in full, with its counts, its activity log, and its deliveries.
64200
"2026-07-16T03:19:00Z"
"2026-07-16T03:20:00Z"
RUNNING, SUCCESS, FAILED, SKIPPED "SUCCESS"
null
What the run started from. On a discovery watch, everything the query returned before the
new-record check and the cap; on a realtime discovery watch, the rows the live retrieval
returned. On an entity watch, the identifiers you listed in entities.
723
Entity watches only. Identifiers that resolved to a record Crustdata holds. A gap between
this and records_searched is the part of your list that matches nothing, which a run
would otherwise pass over in silence. null on a discovery run.
null
Discovery watches only. Matches an earlier run already handled, so records_searched
minus records_stale is records_after_filter. On a job or post watch it counts the
records posted before the last run. null on an entity run.
0
New records the run found, before the cap. On a discovery watch, the new matches. On an entity watch, the entities that changed, and on its first run every subject Crustdata resolved.
723
Records this run delivered. It is below records_after_filter when the cap cut the run short.
5
5
The run's per-stage activity log.
Where the records of this delivery actually travelled. Present on every notification and on
every run summary, so read type before reaching for url.
An inline delivery carries {"type": "inline"} and nothing else, and its records sit in the
body under results. A link delivery carries the whole block and no records: fetch url
with a plain GET and no authorization header, since the pre-signed S3 URL carries its own
authentication in the query string.
The file is NDJSON, one complete JSON object per line with no wrapping array, so you can stream
it without holding the run in memory. Each line is the record the inline body would have
carried: the raw dataset record for a discovery watch, without the added wrapper, and the
same {changes, record} object for an entity watch.
A watch set to link still reports inline here when the file could not be written. The
delivery then carries its records in the body as usual, so an outage costs the link and not the
notification.
Every delivery this run attempted, with the records it carried. Empty unless status is
SUCCESS: a run can leave rows behind without ever paying for or delivering them, and
those rows are not readable here.
When payload_delivery.type is link, each entry keeps its outcome (sent_at,
http_status) and drops payload: the records are in the linked file, and repeating
the link per entry would only be noise.

