Products
LLM Research
LLM Research combines search results and provider-generated synthesis with source links, and reads the pages those links point to. Available results depend on the query, configured providers, and source coverage. A returned citation does not establish that the information is current.
What's inside
Four complementary research surfaces, the last of them a product of its own:
- Web Search (
/web_search): Combines link results, synthesis, and optional social research. Inspect the returned sources and available coverage for each query. - Page reading (
/fetch_url): Reads one page you already have the URL for, usually a link Web Search returned, and gives back its readable body as markdown with the domain's trust tier. - Research Synthesis (
/synthesis): Provider-generated research prose with source URLs. Review the cited material before using its claims. - X/Twitter Sentiment (
/x_sentiment, the Social Sentiment product): a model-written social narrative for a ticker or free-form query, with the sources it searched. It is not a verified, complete feed of current posts.
A typical flow is search first, then read the two or three links that carry the answer.
/fetch_url is not a search tool: it does not discover pages.
Publication dates and freshness
Search results can have a missing or null published date. Treat their publication
time as unknown. The envelope's timestamp records response generation, not source
publication, and cannot establish that a result is recent. A successful response
or a citation alone does not guarantee real-time information.
date_evidence preserves the provider's date meaning. A date labeled
published_or_modified does not prove publication time; last_modified_date and
relative-age hints remain distinct from published. Missing dates are never
replaced with retrieval time. Inspect the evidence type as well as the value.
Check the linked source and any supplied publication date before making a
time-sensitive claim. Responses may be cached; cached describes response reuse,
not the freshness of the source material. freshness on Web Search asks for results
from the past day, week or month; still check each result's date.
Access
6 credits per call. Pro and up (Enterprise also supported).
/api/v3/research/x_ is the Social Sentiment product (social_sentiment): 2,500 credits per call, Pro and up. Each answer runs a live grounded search that costs far more than the other research calls. A repeat of the same ticker or query within 5 minutes is served from that answer and billed the same. AI company analysis (/api/) also bills as LLM Research; see Fundamentals.
Endpoints
| Method | Path | MCP tool | Description |
|---|---|---|---|
GET | /api/v3/research/web_ | research_web_search | Search links, synthesis, and optional social research; source publication dates may be missing. query (required), providers (comma list of links, synthesis, social; default links,synthesis), freshness (pd, pw or pm: past day, week or month), count (results per provider, 1–20, default 5). |
GET | /api/v3/research/fetch_ | research_fetch_url | Read one page as clean markdown with title, author, published date, word count and the domain's trust tier; handles paywalls. url (required, absolute http(s) URL), max_chars (500–10000, default 8000; the domain's trust tier can cap it lower). |
GET | /api/v3/research/synthesis | research_synthesis | Citation-rich research synthesis (grounded LLM). Returns prose + source URLs. ?query= is required; ?system_prompt= is optional. |
GET | /api/v3/research/x_ | research_x_sentiment | 2,500 credits, billed as Social Sentiment. The live X/Twitter read on a name (retail sentiment, breaking rumours, unusual social activity), not a news article list: ticker=NVDA for a focused read on one name, or query for a free-form social-media question; pass at least one. Returns a model-written narrative (is_model_output: true) and any source URLs it grounded against; grounded says whether the model searched X. There is no structured bullish/bearish ratio, and prices, moves and counts in the text are not checked against market data: quote numbers from the market-data routes. When the provider does not answer, the call is a 503 upstream_unavailable (error_), not billed. |
Page reading: trust tiers
/fetch_url classifies the page's domain and caps how much text it returns:
source_tier | Domains | reliability | Characters returned, at most |
|---|---|---|---|
| 1 | Official and institutional sources | 1.0 | 10,000 |
| 2 | Financial media | 0.7 | 8,000 |
| 3 | Opinion and analysis sites | 0.3 | 2,000 |
| 3 | Domains not on any list | 0.1 | 500 |
max_chars can lower the cap but not raise it. truncated: true means the body was cut at
the cap.
Blocked domains are not fetched. A URL that is blocked, not public, or cannot be fetched still
answers 200, is billed, and carries error ("Domain blocked by policy" or
"Failed to fetch URL") with an empty body. Its source_tier and reliability are then the
defaults, 3 and 0.1, not a rating of the domain. Check error before you read body: on success
it is an empty string, not null, and author and published_date are also empty strings when
the page does not state them.
The body is wrapped in [external_content] and [/external_content] markers, and text that
looks like an instruction to a model (such as "ignore previous instructions") is replaced with
[redacted]. Treat the body as untrusted page text. word_count includes the markers.
Pages are cached by URL for up to 30 minutes, and a cached page keeps the length it was first
read at. Within that window a request with a different max_chars can get a body cut at the
earlier request's length.
Examples
Bash: Multi-provider web search
The response below illustrates the shape with placeholder text, not a captured result or a financial claim. Its null publication date demonstrates unknown source age; returned fields and provider coverage vary by request.
curl -H "Authorization: Bearer $WEALTHNOW_API_KEY" \ "https://firm.wealthnow.io/api/v3/research/web_search?query=NVIDIA%20earnings%20Q4%202024&providers=links,synthesis&count=5" # Illustrative response structure, not live evidence:# {# "ok": true,# "timestamp": "2024-12-16T14:22:00Z",# "query": "NVIDIA earnings Q4 2024",# "providers_used": ["links", "synthesis"],# "synthesized_answer": "<Provider synthesis; verify claims against the linked source.>",# "citations": [# {"url": "https://example.com/source", "title": "Example source"}# ],# "results": [# {# "title": "Example source",# "url": "https://example.com/source",# "snippet": "<Excerpt from the source.>",# "published": null,# "source_provider": "links"# }# ],# "total_results": 1,# "total_tokens": 1250,# "cached": false,# "search_time_ms": 3420# }Add freshness=pw to keep the search to the past week.
Bash: Read one page from the results
Pass a link from the search results. The response below shows the fields with placeholder values; it is not a captured page.
curl -G -H "Authorization: Bearer $WEALTHNOW_API_KEY" \ "https://firm.wealthnow.io/api/v3/research/fetch_url" \ --data-urlencode "url=https://example.com/source" \ --data-urlencode "max_chars=4000" # Illustrative response structure, not live evidence:# {# "ok": true,# "timestamp": "2024-12-16T14:23:10Z",# "url": "https://example.com/source",# "title": "Example source",# "body": "[external_content]\n<The page's readable text as markdown.>\n[/external_content]",# "author": "",# "published_date": "",# "word_count": 84,# "source_tier": 3,# "reliability": 0.1,# "truncated": true,# "error": ""# }Here example.com is on no domain list, so the body stops at 500 characters whatever
max_chars asked for, and truncated is true.
Python: Research synthesis with custom system prompt
import os, requests r = requests.get( "https://firm.wealthnow.io/api/v3/research/synthesis", params={ "query": "What are the key headwinds and tailwinds for Apple in 2025?", "system_prompt": "You are a skeptical equity analyst. Cite all sources. Be precise on numbers." }, headers={"Authorization": f"Bearer {os.environ['WEALTHNOW_API_KEY']}"}, timeout=30,)r.raise_for_status()data = r.json() # Extract the research envelopeprint(f"Provider: {data['provider']}")print(f"Answer:\n{data['answer']}")print(f"Sources: {data['sources']}")print(f"Citations:\n" + "\n".join(c["title"] for c in data["citations"])) # Each call costs 6 credits; check wallet balance in the dashboard