POST /v1/keywords with different
terms, and GET /v1/mentions with two filters.
1. Search for the sentence, not the name
A brand keyword looks for one token. A discovery keyword looks for the phrases people type when they are stuck:terms are OR’d into one upstream call, so several phrasings of the same
complaint cost one poll, not three.
A topic keyword sent without a match is created with match: "word": an
item is kept only when it carries one of the phrases as written. That is what
keeps a phrase keyword readable, because most platforms answer a phrase with
whatever they think is near it. When people type your phrases too many
different ways and the keyword stays quiet, send "match": "contains" to widen
it. "match": "platform", stated explicitly, keeps the platform’s own matching.
Write the phrases in the words your customers use, not the words you use.
“Brand monitoring” is your category; “I keep missing when people mention us”
is their problem.
2. Poll the places people describe problems in prose
Five sources carry that kind of sentence. Enable them together:3. Switch the readings on
A phrase keyword catches everyone who used the phrase, and most of them are not prospects: someone answering, someone quoting, someone complaining about a different tool. Two readings sort them, and they are what step 4 filters on.sentimentEnabled reads every mention as positive, neutral, negative,
question or mixed. aiEnabled also writes the intent — what the item is
trying to do: purchase_intent, comparison, question, complaint, praise
or other.
Both cost credits per classified item. Without them, step 4 has nothing to
filter on.
A third reading tells a prospect from a bystander: an agent step asked of
every mention. Give it a boolean problem_fit field and it becomes what the
opportunity filter of step 4 reads:
subjectRole costs nothing. It says what this keyword is about (here a problem
rather than a product), it sets the default match of step 1, and it is what a
reply draft reads to decide whose voice it writes in. Leave it out and the
keyword is own, which is right for a brand keyword and wrong for this one: a
draft would answer as if the pain phrase were your company’s name.
4. Read back only what needs you
GET /v1/mentions filters on both readings. Each is repeatable, and repeated
values are OR’d:
topic or competitor keyword that is highly
relevant to it (relevance: high) and whose author is someone to answer. On a
keyword whose step has a boolean problem_fit, that is problem_fit: true
under the step it carries now; on any other, an intent of purchase_intent,
comparison or question. An own keyword has none. The same parameter works
on GET /v1/keywords/{id}/results, and the dashboard’s Feed offers it as
Opportunities, at the head of the Intent filter.
Repeated values of one key are OR’d; different keys are AND’d. So
?source=reddit&source=hackernews&sentiment=negative&intent=complaint reads:
on Reddit or Hacker News, negative, and a complaint. source, sentiment and
intent are all repeatable.
unread is the wire spelling of “not yet classified” — a real filter value, not
an absence. It is how you find what your readings have not caught up with.
Cutting the mentions nobody reacted to
engagement_min keeps mentions with at least that many interactions — likes,
replies, reposts, comments or score, whichever the Source reports. It is the
noise gate for a busy Source: on a typical month of X mentions, roughly seven in
ten have no interactions at all, so ?engagement_min=1 alone removes most of
what you would otherwise page through.
Three things it does not do, each of which will otherwise surprise you:
- It never counts views. A view is not an interaction, and on the Sources that report one it is an order of magnitude bigger than every other counter — including it would make this a filter on reach.
- It leaves out mentions with no counters at all, rather than treating them
as zero. RSS items and AI answers report no audience, and mentions recorded
before 4 September 2026 predate the field. None of them were measured, so none
can satisfy a threshold.
?engagement_min=0is therefore narrower than no filter: it asks for everything that was counted. - The numbers are captured when we collect a mention, and never refreshed. A post caught two minutes after it went up is measured with the counters it had then. So a threshold reads against your most recent mentions, which are the ones with the least time to have earned anything.
engagement below is for.
Asking a different question of each Source
engagement_min thresholds one number for everything, and the sum it thresholds
is lossy: a post with a hundred replies and no likes clears engagement_min=100
exactly as a post with a hundred likes does, and those are not the same
mentions. It was liked and it was argued with is the distinction a sum
erases.
engagement is a rule, and it is repeatable:
- Metrics are
likes,replies,reposts,comments,scoreandviews, plustotalfor the same interaction sumengagement_minreads.engagement_min=10is exactlyengagement=*:total>=10. - Operators are
>=,>,=,<and<=. The number is whole and may be negative — Reddit and Lemmy net downvotes out, so?engagement=reddit:score<0is a real question: the mentions that were argued with. *stands for any Source no named rule already covers. Pair it withtotal—?engagement=*:total>=25is “at least 25 interactions, wherever it was said”, which isengagement_minwith an operator of your choosing. A named counter under*is legal but rarely what you mean:*:likes>=100drops every Source that does not count likes, by the rule below.
- A Source no rule names passes.
?engagement=x:likes>=100narrows X and leaves Hacker News exactly as it was. Without that, every rule would also be a Source filter in disguise — and?source=already exists for that. A named rule overrides*for its own Source, and several rules on one Source are ANDed. - A metric that was never counted satisfies nothing —
<included. This is theengagement_minrule above, one level down and sharper: YouTube reports no likes at all, so?engagement=youtube:likes<10returns none of your YouTube mentions rather than all of them. Only a metric the Source actually reports can be filtered on.
engagement or engagement_min, never both: they are two spellings of one
filter, and a request carrying both is a 400.
Every mention comes back with both readings on it, so you can sort further
without a second call:
5. Qualify each one with your own question
The readings say what an item is. To ask whether it is your problem, give the keyword an agent step (one instruction and a schema, applied to every item it catches):agent, spelled with your own field
names:
current_workaround is the one with commercial value beyond triage: what
someone names as their current answer is what your reply has to be better than.
See AI for the schema’s field types and what an agent pass costs.
6. Get told instead of polling
Do not poll/v1/mentions on a timer. A keyword delivers what it catches to a
webhook, and every mention arrives with its readings already on it,
so the filter that reads well in step 4 becomes a condition in your own
handler.
What this does not do
It finds people describing a problem. It does not find customers, and it does not tell you they want to buy — aproblem_fit of true is a reading of
one post, not a qualified lead. Treat the output as a list of conversations
worth joining, and expect to discard some of it.