Query Signal Detections
Paginate the signal detections published for your workspace.
Signal detection endpoints expose published signal detections for the authenticated workspace. This includes detections produced by keyword runs and any manually added detections. All items are workspace-scoped.
This endpoint uses cursor pagination instead of the standard offset envelope. Pass
the next_cursor from each response as the cursor field of the next request. To get a
total count, call Count signal detections
with the same filters (except type, which the count endpoint does not accept).
Request body
| Field | Type | Description |
|---|---|---|
| cursor | string | Opaque pagination cursor. Pass the next_cursor from the previous response to fetch the next page. Omit for the first page. |
| limit | integer | Number of items to return per page (1–100). Defaults to 25. |
| signal_start_date | string (date-time) | Return detections whose signal date is on or after this timestamp (ISO 8601 with UTC offset). Defaults to 90 days before now. Cannot go further back than 180 days — an older value is clamped to that limit. |
| signal_end_date | string (date-time) | Return detections whose signal date is on or before this timestamp (ISO 8601 with UTC offset). |
| detection_start_date | string (date-time) | Return detections that were first seen on or after this timestamp (ISO 8601 with UTC offset). |
| detection_end_date | string (date-time) | Return detections that were first seen on or before this timestamp (ISO 8601 with UTC offset). |
| agent_id | integer | Return detections produced by a specific agent. Pass the numeric agent_id returned on each detection. |
| signal_run_id | integer | Return detections from a specific run. Pass the numeric run id from the signal-runs endpoint. When no date filter is supplied, results default to the 90 days before the run's creation. |
| type | string[] | Return only detections of these signal types. Native JSON array of at least one value from: keywordDetection, newJob, recentlyPromoted, jobPostingKeywordDetection, competitorInboundComment, competitorOutboundComment, partnerInboundComment, partnerOutboundComment, customerInboundComment, customerOutboundComment, influencerInboundComment, influencerOutboundComment, championInboundComment, championOutboundComment, championJobChange — an unknown value is rejected with a 400. Pass ["championJobChange"] to isolate champion job changes; that type covers every champion career move, including departures where the new company is not known yet. Not supported by the count endpoint. |
| company_id | integer | Return detections for a specific company on your top-account list. Pass the numeric company_id from your target account list. This ID is specific to your environment. Taken at face value — a company that exists in your workspace but is not on your top-account list returns an empty page, not a 404. |
| company_domain | string[] | Return detections for companies on your top-account list matching these domains. Native JSON array for OR filtering across multiple companies (e.g. ["acme.com", "widgets.io"]). Returns 404 when none of the supplied values resolve to a known company on your top-account list. |
| company_linkedin_handle | string[] | Return detections for companies on your top-account list matching these LinkedIn handles. Native JSON array (e.g. ["acme-corp", "widgets-io"]). Returns 404 when none of the supplied values resolve to a known company on your top-account list. |
| company_linkedin_url | string[] | Return detections for companies on your top-account list matching these LinkedIn URLs. Native JSON array. Returns 404 when none of the supplied values resolve to a known company on your top-account list. |
| lead_id | integer | Return only signals directly linked to this lead. Pass the lead_id carried by signal items; resolve details via Get lead. Only matches signals directly linked to the lead — not signals attributed through fallback matching. |
| countries | string[] | Return only signals whose linked lead is located in one of these countries. Native JSON array of country names from GET /workspace-leads/locations. Combined with cities. Only matches signals directly linked to a lead — company-only signals are excluded. |
| cities | object[] | Return only signals whose linked lead is located in one of these cities. Each entry is { "name": "Paris", "country": "France" }. Use the values from GET /workspace-leads/locations. Only matches signals directly linked to a lead. |
Results are sorted by detection date descending (most recent first).
Example request
curl -X POST "https://api.getsillage.com/api/v2/workspace/signals/query" \
-H "Authorization: Bearer $SILLAGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"limit":25}'Example response
200 OK
{
"data": [
{
"id": 101,
"signal_type": "keywordDetection",
"data": {
"content_id": 5100,
"author": {
"type": "profile",
"full_name": "Jane Doe",
"headline": "VP Product at Acme",
"linkedin_url": "https://linkedin.com/in/janedoe"
},
"keywords_found": ["AI"]
},
"detected_at": "2026-06-01T10:00:00.000Z",
"signal_date": null,
"lead_id": 456,
"company_id": 789,
"agent_id": 12,
"source_url": "https://www.linkedin.com/feed/update/urn:li:activity:7100000000000000000/",
"author": {
"full_name": "Jane Doe",
"headline": "VP Product at Acme",
"linkedin_url": "https://linkedin.com/in/janedoe"
},
"excerpt": "Excited to share how AI is transforming our product roadmap this quarter."
}
],
"meta": {
"next_cursor": "eyJkZXRlY3RlZEF0IjoiMjAyNi0wNi0wMVQxMDowMDowMC4wMDBaIiwiaWQiOjEwMX0=",
"has_more": true
}
}To fetch the next page, pass next_cursor as cursor in the body of the subsequent request. When has_more is false, you have reached the last page and next_cursor will be null.
For keyword detections, data.content_id is the ID of the content the keyword matched in (usable with the Contents endpoints), and data.author describes who published it, discriminated by type: "profile" (a person — full_name, headline, linkedin_url) or "company" (a company page — company_name, linkedin_url). author is null when the publisher is unknown.
The top-level source_url, author, and excerpt fields are convenience shortcuts to the most relevant link, person, and text extract already present somewhere in data (or, for a few signal types, only reachable outside the current data shape) — read them directly instead of digging through the type-specific data payload. The top-level author is not always the same object as data.author: for detections where the source content and the person are separate concepts (e.g. a comment left by someone else on a tracked post), the top-level author follows a fixed per-type priority so it consistently points at the person behind the source content.
Detection object fields (V2SignalDetection)
| Field | Type | Description |
|---|---|---|
| id | integer | ID of the detection. Specific to your environment. |
| signal_type | string | null | Signal type, e.g. keywordDetection, championJobChange. |
| data | any | null | Detection payload; the shape depends on signal_type (see the sections below). |
| detected_at | string (date-time) | null | When the detection was created. |
| signal_date | string (date-time) | null | Date of the underlying signal event. |
| lead_id | integer | null | ID of the associated workspace lead. For detections without their own lead (e.g. keyword matches), this is the content author's lead when known. Null when the author is unknown. |
| company_id | integer | null | ID of the associated workspace company. |
| agent_id | integer | null | ID of the agent that produced the detection. |
| source_url | string | null | Link to the source content behind the detection (the post, interaction, or job posting). null when the detection has no public external link. Presence depends on signal_type. |
| author | object | null | The person behind the source content, when known: full_name, headline, linkedin_url (each nullable). null for company-level or authorless detections. |
| excerpt | string | null | A short text excerpt from the source content (post text, comment, or job description). null when no text is available. |
Interaction agent comment detections
Detections produced by interaction agents (signal types ending in InboundComment or OutboundComment, e.g. competitorInboundComment) use a dedicated data shape: the comment on one side (interaction), the post it was left on the other (post). Each side carries a content_id — the ID of the matching content in your workspace, usable with the Contents endpoints. content_id is null when no matching content exists in your workspace.
{
"interaction": {
"type": "comment",
"content_id": 5001,
"author": {
"full_name": "Jane Doe",
"linkedin_url": "https://linkedin.com/in/janedoe",
"headline": "VP Product at Acme"
}
},
"post": {
"content_id": 5002,
"author": {
"full_name": "John Smith",
"linkedin_url": "https://linkedin.com/in/johnsmith",
"headline": "Head of Sales at Widgets"
}
}
}Errors
| Status | Meaning |
|---|---|
| 400 | Invalid request body. |
| 401 | The API key is missing or invalid. |
| 403 | The workspace does not have access to this resource. |
| 404 | Returned when string company identifier(s) (company_domain, company_linkedin_handle, or company_linkedin_url) were supplied and none resolved to a known company in your workspace. company_id is never validated and never triggers a 404. |
| 429 | Rate limit exceeded. |
| 500 | An unexpected server error occurred. |
Error responses use RFC 9457 problem documents with Content-Type: application/problem+json:
{
"type": "https://docs.getsillage.com/errors/not-found",
"title": "Not Found",
"status": 404,
"detail": "No matching company found for the supplied identifiers.",
"instance": "/api/v2/workspace/signals/query"
}