Skip to main content
GET
Get one signal

Authorizations

Authorization
string
header
required

A workspace API key, created in workspace settings and sent as Authorization: Bearer op_live_…. Session cookies are not accepted. Scopes: signals:read, accounts:read, listeners:read, listeners:analyse, pipeline:read, pipeline:write, collections:write, export:read.

Path Parameters

id
string
required

The signal's id.

Response

The signal, outside every window and every page. Unlike the list, this applies no postedAt bound — a lead found yesterday but published five weeks ago is returned here and is not in the list that links to it.

One public post, job posting or review a listener judged relevant, with its score and the reasoning behind it.

Most fields are optional and that is structural, not incidental. Rows are stored by a pipeline that has gained stages over time, and a field added after a row was written is absent from it for ever: nothing is re-scored, because that is a model call per signal for no new information. Read defensively.

id
string
required

Stable identifier. What GET /v1/results/{id} takes.

orgId
string
required

The workspace this belongs to (org_…).

listenerId
string
required

The listener that found it.

source
enum<string>
required

The platform it came from.

Available options:
x,
linkedin,
facebook,
reddit,
hackernews,
linkedin_jobs,
indeed,
ashby,
greenhouse,
lever,
google_reviews,
g2,
trustpilot,
youtube
url
string<uri>
required

Link to the post itself.

title
string
required

The post's title, or its first line where the platform has none.

excerpt
string
required

The post's text, as much of it as the source gave up. See coverage.

postedAt
string<date-time>
required

The sort and filter key: publishedAt when known, otherwise firstSeenAt.

relevanceScore
integer
required

0–100. The sort order of every list in the product.

Required range: 0 <= x <= 100
classification
enum<string>
required

The intent label. The valid set depends on the listener's mode — a market listener never produces pain_confirmed — so filtering by one from the wrong mode returns an empty page rather than an error. The retired jobs labels are still valid here: no listener produces them, and signals carrying them are still stored and still read.

Available options:
high_intent,
evaluating,
relevant,
competitor,
content,
strong_match,
worth_a_look,
stretch,
mismatch,
stale,
hiring_now,
expanding,
replacing,
adjacent,
switching,
frustrated,
comparing,
praise,
pain_confirmed,
at_risk,
healthy,
noise
rationale
string
required

Why this was kept, in the model's words.

matchedKeywords
string[]
required

Computed from the text, never taken from the model.

A keyword from the listener's plan.

firstSeenAt
string<date-time>
required

When this workspace first saw it, which is not when it was published.

author
string

The poster's handle, where the source reports one.

publishedAt
string<date-time>

When the post was published, when the source reports it.

approximateDate
boolean

True when publishedAt was derived from "3 months ago" rather than a real timestamp. Rendered as ~, because implying a precision the source never gave is worse than admitting the approximation.

dedupeKey
string

Normalised URL, used to collapse one post reached through different links.

titleKey
string

Normalised title, used to collapse one post syndicated across URLs.

coverage
enum<string>

How much of the post the classifier actually read. snippet and best_effort cap the evidence component of the score; enriched means the page behind a snippet was fetched. Absent on rows written before the enrichment stage.

Available options:
full_text,
snippet,
best_effort,
enriched
scoreVersion
enum<integer>

Which rubric produced relevanceScore. No version is comparable to another and they sort against each other in the same column, which is why they are marked rather than silently mixed. Absent means 1.

Available options:
1,
2,
3
scoreBreakdown
object

The seven components the score is the sum of, each capped at its own weight. Present only on scoreVersion 2 and 3. The components are the point rather than the total: "86" says nothing, "26 of 30 on intent, 8 of 20 on fit" says a real buyer who is probably not yours.

signalCategory
enum<string>

What kind of event this is, as opposed to how good it is. Orthogonal to classification: a funding round and a support complaint can both be high_intent, and are not actioned by the same person.

Available options:
direct_intent,
hire_vs_buy,
competitor_pain,
growth,
funding,
procurement,
construction,
regulatory,
operational_pain,
tech_change,
leadership_change,
real_estate,
new_business,
cx_failure,
missing_capability,
incident
urgency
enum<string>

How soon this needs acting on.

Available options:
low,
medium,
high,
immediate
purchaseIntent
enum<string>

How directly a wish to buy was expressed.

Available options:
weak,
moderate,
strong,
explicit
confidence
enum<string>

How much the model trusts its own read.

Available options:
low,
medium,
high
inferredNeed
string

What the subject probably needs: the product-shaped restatement.

The single next action worth taking.

situation
string

What is happening, stated without reference to the seller. Separate from opportunity so the leap between them is checkable by whoever reads the row.

opportunity
string

Why that situation matters to this seller, or absent when it does not.

inferenceHops
enum<integer>

How far the reasoning reached: 0 they said it, 1 one step from what they said. There is no 2 — two stacked assumptions are indistinguishable from invention, and the prompt refuses it.

Available options:
0,
1
suggestedAngle
string

One line on why this person might care: the outreach angle.

themes
string[]

Two to four phrases naming what the post is about.

A short noun phrase.

rating
number

Star rating 1–5 on a review source. Never the same number as relevanceScore.

Required range: 1 <= x <= 5
subjectOrg
object

The organisation the signal is about, which is not the poster. Every field is optional and absent is the common case: most conversations name no company, and inventing one from the platform host would file the whole corpus under one domain.

subjectName
string

Display name of the place or rival, so a row reads without a join.

accountKey
string

The company this is about, namespaced (d:acme.com for a domain, n: for a name, p: for a place). Absent is a real and common answer — a thread that names no company has none.

rivalKey
string

Which rival this is about, on a rivals listener.

placeKey
string

Which place this review belongs to, on a places listener.

policy
object

What the surfacing policy did when this signal was stored, for off-policy evaluation. Absent on every signal written before the holdout existed — and absent must read as "unknown", never as a propensity of 1.

passedBy
enum<string>

How this got past the on-topic gate. rerank means it shares no keyword and the cross-encoder judged it relevant anyway.

Available options:
keyword,
rerank
rerankScore
number

Cross-encoder relevance, when the rerank stage ran.

foundByQuery
string

Which planned query surfaced this, for per-query yield reporting.

queryAttribution
enum<string>

Whether foundByQuery is known or was worked out afterwards from token overlap. Recorded because per-query yield decides which queries get retired.

Available options:
exact,
inferred
assignedTo
object

Who is working this lead. Set through PATCH /v1/results/{id}/assign.

feedback
object

A person's verdict on the signal, which the classifier reads back.

readAt
string<date-time>

When somebody in the workspace read it. Workspace-wide rather than per member: a signal is a lead somebody acts on once. Absent means unread.

alertedAt
string<date-time>

When an urgency alert was sent for this. Absent means never.