Audience intelligence
Give a topic or a brand website, get back what real people say about it in public comments and discussions: the words they use, the questions they ask, what they expect from a product, where they disagree with creators, what is missing in existing content and which themes are growing. Every finding is counted across independent threads and linked to the comments it came from, so your team or your own AI model can check it.
One research job reads one sample of up to 500 accepted comments and turns it into all nine products (views of the same data) below. Every job includes all nine; you may name the one you care about most.
products value | What you get |
|---|---|
audience_keywords | phrases the audience uses, grouped by meaning (frequency in comments, not search volume) |
audience_questions | recurring questions with variants, funnel stage and whether creators already answer them |
website_requirements | what a website must say or show: features, integrations, pricing, proof, objections; each marked must, should or could |
comparison_intelligence | how the audience compares named products: dimensions, switching triggers, trust gaps |
content_brief_from_audience | a content brief: working title, sections, questions to answer, objections, FAQ, claims to avoid |
audience_content_gaps | demand that existing answers cover poorly, with the asset to create |
creator_vs_audience_gap | where commenters disagree with, question or add conditions to what creators claim |
buyer_expectations | what buyers take for granted (must_have) and what sets a product apart (differentiator) |
trend_from_audience | themes that are rising, stable or declining, normalised per 1,000 relevant threads |
Audience intelligence is switched on for a key on request: write to support@omev.be. Jobs are charged to the key's usual balance.
Price
| What | Price |
|---|---|
| One research job, all nine products included | $0.99 |
The price is charged once, when jobs/create accepts the job. A job that ends NO_DATA
(not enough relevant public discussion) is free; a COMPLETED_PARTIAL job is charged in
full. Repeating jobs/create with the same idempotency_key returns the same job and is
not charged again. estimate, jobs/get, jobs/result and jobs/cancel are free.
Check the request first
estimate validates the body, shows the normalised scope and the price, and starts no
work. It takes the same body as jobs/create; idempotency_key is optional here.
curl -sS https://llmapi.omev.be/v1/audience-intelligence/estimate \
-H "Authorization: Bearer $OMEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"schema_version": "1.2",
"products": ["audience_questions", "buyer_expectations"],
"topic": {"name": "waterproof sneakers for commuting"},
"audience": {"description": "city commuters who walk in the rain"},
"scope": {"platforms": ["youtube", "reddit"], "languages": ["en"], "markets": ["US"]}
}'
{
"request_id": "…",
"supported": true,
"normalized_scope": {
"markets": ["US"], "languages": ["en"],
"from": "2026-03-31T10:00:00Z", "to": "2026-09-27T10:00:00Z",
"platforms": ["reddit", "youtube"]
},
"sample": {"target_accepted_comments": 500, "consent_required": false},
"quote": {
"customer_cost_usd": "0.99000000", "currency": "USD", "tier": "single",
"products": ["audience_content_gaps", "audience_keywords", "audience_questions", "…"],
"valid_until": "2026-09-27T11:00:00Z"
},
"estimated_completion_seconds": {"min": 20, "typical": 240, "max": 1800},
"warnings": []
}
quote.customer_cost_usd is the price of the job. supported: false or a note in
warnings means a data source is temporarily unavailable: try again later.
Start a research job
curl -sS https://llmapi.omev.be/v1/audience-intelligence/jobs/create \
-H "Authorization: Bearer $OMEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"schema_version": "1.2",
"idempotency_key": "acme-17-sneakers-2026-09",
"products": ["audience_questions", "buyer_expectations"],
"topic": {"name": "waterproof sneakers for commuting"},
"audience": {"description": "city commuters who walk in the rain"},
"scope": {"platforms": ["youtube", "reddit"], "languages": ["en"], "markets": ["US"]}
}'
| Field | Required | Meaning |
|---|---|---|
schema_version | yes | 1.0, 1.1 or 1.2; use 1.2 |
idempotency_key | yes for jobs/create | 8–200 characters; repeating it returns the same job instead of starting a new one |
product or products | no | the product you care about most, or a list of products from the table above; at most one of the two fields. The job builds all nine either way |
topic.name | name or website_url | the subject, 3–300 characters |
topic.website_url | name or website_url | a brand site; the brand name is read from the site |
topic.description | no | up to 2,000 characters that sharpen the subject |
topic.include_terms, topic.exclude_terms | no | up to 50 terms each to widen or narrow what counts as relevant |
audience.description | no | who you want to hear from, 3–2,000 characters |
audience.roles, audience.company_size | no | extra hints for business audiences |
scope.platforms | no | any of youtube, reddit, linkedin, tiktok, instagram, threads, facebook, twitter, web |
scope.languages | no | comment languages, default ["en"], up to 10 |
scope.markets | no | country codes such as ["US"]; empty means worldwide |
scope.period | no | {"days": 7…365} (default 180) or {"from": "…Z", "to": "…Z"} in UTC, 7–365 days apart |
entities | no | products or companies to compare: {"name": "…", "kind": "product", "aliases": ["…"]}; without them comparison_intelligence uses the comparisons found in the comments |
creator_seeds | no | channels or communities to read: {"platform": "youtube", "url": "https://…"}; a Reddit community is https://www.reddit.com/r/<name>, a single Reddit thread is a thread URL with "kind": "publication" |
source_mode | no | discover (default) finds sources itself; seeds_only reads only your creator_seeds |
data_mode | no | refresh_if_needed (default) reuses recent data for the same scope and tops it up; fresh collects anew; corpus_only uses only data already collected for your account |
output | no | max_signals (1–100, default 30), max_evidence_per_signal (1–20, default 5), include_short_quotes and include_markdown (both default true) |
limits | no | max_creators (default 30, up to 100), max_publications (default 300, up to 1,000), max_comments (default 15,000, up to 50,000), deadline_seconds (default 1,800, 60–3,600) |
Defaults that matter:
- With only
topic.website_url, the job reads every platform and also independent forums and blogs. - With
topic.nameand noscope.platforms, the job reads YouTube only. List the platforms you need.
The answer is 202 with the job:
{
"request_id": "…",
"job": {"id": "aij_…", "status": "QUEUED", "stage": "VALIDATE", "progress": 0,
"created_at": "…", "deadline_at": "…", "currency": "USD", "warnings": []},
"idempotent_replay": false,
"poll_after_seconds": 3
}
Follow the job
A job usually takes a few minutes and stops at limits.deadline_seconds at the latest.
Poll every 5–10 seconds.
curl -sS https://llmapi.omev.be/v1/audience-intelligence/jobs/get \
-H "Authorization: Bearer $OMEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{"job_id": "aij_…"}'
job.progress runs from 0 to 100; job.coverage_so_far shows the counts collected so far.
status | Meaning |
|---|---|
QUEUED, RUNNING | waiting or working |
WAITING_PROVIDER, RETRY_WAIT | waiting for a data source or retrying; keep polling |
COMPLETED | the report is ready |
COMPLETED_PARTIAL | a report is ready but the sample is smaller than planned; see warnings and product_readiness |
NO_DATA | not enough relevant public discussion was found; there is no report |
BUDGET_EXHAUSTED, EXPIRED, FAILED | the job ended without a full report; stop_reason and public_error_code say why |
CANCELLED | you cancelled the job |
To stop a job, send {"job_id": "aij_…"} to /v1/audience-intelligence/jobs/cancel.
The answer is 202 while the job stops, or 200 if it is already cancelled.
Download the report
curl -sS https://llmapi.omev.be/v1/audience-intelligence/jobs/result \
-H "Authorization: Bearer $OMEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{"job_id": "aij_…"}'
Before the job ends the call returns 409 JOB_NOT_READY. A job that ended without a
report (for example NO_DATA) returns {"job": {…}, "report": null}.
The report:
| Field | Contents |
|---|---|
status, products | the final status and the products built |
product_results | one object per product, keyed by product name; each holds an items list in the shape of that product |
product_readiness | per product: sufficient, insufficient_sample or no_evidence, with the reason |
summary | a short plain-language summary |
research_question, scope | what was studied: topic, audience, period, platforms requested and actually observed |
methodology | whose opinions the sample represents, how sources were selected, limitations |
coverage | comments collected, accepted and excluded, unique threads, platforms, the largest share of one source |
signals | the underlying findings: type (question, pain point, expectation, objection, comparison, trend…), label, strength (anecdotal, emerging, recurring, strong), counts and evidence_ids |
evidence | the comments behind the findings: platform, publication, comment text, relevance |
contradictions, warnings | findings that conflict, and anything that limits the report |
rendered_markdown | the same report as Markdown, when output.include_markdown is true |
Counts are unique discussion threads, not raw comments, so one loud thread cannot make a
theme look big. Treat anecdotal findings as hints, not facts.
Reports stay available for 90 days after the job ends; after that the call returns
410 RESULT_EXPIRED.
Narrow topics
A job aims at 500 accepted comments, the maximum. For a niche where that many do not
exist, you can accept a smaller sample of 200–499 comments at the same price: set
sample_policy.mode to narrow, sample_policy.target_accepted_comments to the target,
and add sample_policy.narrow_topic_consent with the registered consent wording, the
time it was accepted and the policy version. Contact
support@omev.be for the exact wording before you build this
into a product.
Errors
| Code | When |
|---|---|
401 | missing or invalid API key |
403 | the key cannot use this product |
404 | unknown job, or a job that belongs to another account |
409 JOB_NOT_READY | the report was requested before the job finished |
409 IDEMPOTENCY_CONFLICT | the idempotency_key was already used with a different body |
409 JOB_ALREADY_TERMINAL | cancel was sent for a job that has already finished |
410 RESULT_EXPIRED | the report is older than 90 days |
422 INVALID_ARGUMENT | a field is missing or out of range; the body names the field |
429 | too many requests or too many jobs in the queue; retry after a short pause |
For 409, 410 and 422 the body carries the service code shown above. Other statuses
return the common error body, see Errors.