A read + trigger HTTP API for consuming the ideas this engine generates, the research spine behind them (validations, themes, demand signals, gaps, change events, hypotheses, Issues), and kicking off new autonomous runs. Designed for server-to-server use by trusted platforms.
https://YOUR_HOST/api/public/v1All endpoints below are relative to this base. Authenticate with a bearer token (see Authentication).
Authentication
Every request must include a bearer token in the Authorization header. The same key authorizes reading ideas and triggering runs, so treat it as a secret with write power.
Authorization: Bearer YOUR_API_KEYA missing or wrong key returns 401 unauthorized. If the server has no key configured at all, every endpoint returns 503 api_not_configured (fails closed).
/api/public/v1/ideasReturns a filtered, paginated list of generated ideas, newest first (last_updated descending) unless you sort or search. Filter by market size, scores, and ICP; search full text with q. Use updated_since to poll incrementally — store the largest last_updated you've seen and pass it back next time.
| Parameter | Type | Default | Description |
|---|---|---|---|
| updated_since | ISO 8601 | — | Only ideas changed strictly after this timestamp. Invalid value → 400. |
| status | enum | active | active | archived | all. |
| surface | string | — | Match a surface by id (e.g. SURF-019; legacy OPP-019 also accepted) or by name substring. |
| theme | string | — | Match a linked research theme by exact slug (e.g. T012-agentic-commerce) or by name substring. Ideas inherit their parent surface's themes. |
| hypothesis | string | — | Only ideas riding this strategic hypothesis (HYP-004; unpadded HYP-4 accepted). Matches the direct link, the idea's thesis tags, and the parent surface's links — see /hypotheses for the ledger. |
| has_deep_dive | bool | — | true = only ideas whose deep_dive is non-null (own or surface-inherited pack); false = only ideas without one. |
| first_seen_since | ISO 8601 | — | Only ideas first discovered strictly after this timestamp (vs. updated_since, which tracks any change). |
| limit | int | 50 | Page size, clamped to 1–200. |
| offset | int | 0 | Pagination offset (≥ 0). |
Values are absolute dollars, with optional k / m / b / t suffix (case-insensitive): 500k, 20m, 1.5b, 2t.
| Parameter | Type | Default | Description |
|---|---|---|---|
| min_tam / max_tam | USD | — | Floor / ceiling on total addressable market. |
| min_sam / max_sam | USD | — | Floor / ceiling on serviceable addressable market. |
| min_som / max_som | USD | — | Floor / ceiling on serviceable obtainable market. |
| min_cagr | number | — | Floor on 5-year CAGR (%). Negative allowed. |
| min_ltv_cac | ratio ≥ 0 | — | Floor on LTV:CAC (e.g. 3). LTV is the stored value, else unit margin × customer lifetime; ideas missing LTV or CAC are excluded. |
| Parameter | Type | Default | Description |
|---|---|---|---|
| min_conviction | 0–100 | — | Floor on conviction (backend-computed blend). |
| min_attention | 0–100 | — | Floor on the attention score. |
| min_timing | 1–5 | — | Floor on timing. Maps to the window words: 5 active window · 4 accelerating · 3 emerging · 2 weakening · 1 mature. |
| min_asymmetry | 1–5 | — | Floor on asymmetry (upside vs. effort). |
| min_founder_fit | 1–5 | — | Floor on founder-market fit. |
| min_severity | 1–5 | — | Floor on problem severity. |
| min_market_growth | 0–100 | — | Floor on normalized market growth. |
| max_difficulty | 1–5 | — | Ceiling on the founder/difficulty scale (1 solo-friendly … 5 VC-scale team). max_difficulty=2 ≈ solo-buildable. |
| min_votes | int | — | Floor on all-time net votes across members (votes_net). Negative allowed; unvoted ideas count as 0. |
Every floor/ceiling excludes ideas whose value is null (not yet scored or estimated).
| Parameter | Type | Default | Description |
|---|---|---|---|
| business_type | enum | — | b2b | b2c (case-insensitive). |
| build_type | enum | — | software | hardware (case-insensitive, prefix-matched against stored variants). |
| industry | string | — | Case-insensitive substring on the idea's industry vertical, e.g. industry=fintech or industry=health. Vocabulary: Healthcare & Bio · Fintech · Security · DevTools & Infra · Enterprise Software · Consumer · Commerce & Retail · Media & Creative · Education · Legal & Compliance · Industrial & Robotics · Climate & Energy · Cross-industry (see GET /industries for live counts). |
| icp | string | — | Substring match on the idea's ICP text, e.g. icp=developer. |
| Parameter | Type | Default | Description |
|---|---|---|---|
| q | string | — | Full-text search over name, tagline, ICP, problem, solution, thesis, and wedge. Web-search syntax: bare words are AND-ed, "quoted phrases" match in order, -word excludes, or alternates. Max 500 chars. |
| sort | enum | updated · relevance with q | relevance | updated | conviction | attention | tam | sam | som | cagr | votes | ltv_cac. relevance requires q. Nulls sort last. |
| order | enum | desc | asc | desc. |
With q, each row carries a relevance score (name and tagline weigh most, then ICP/problem, then the rest) — values are relative to that query, not comparable across queries. English stemming applies (planners matches planner). A query with no matches returns an empty data array, never an error.
# Incremental sync of high-conviction active ideas
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/ideas?status=active&min_conviction=60&limit=50&updated_since=2026-06-01T00:00:00Z"
# Big-market B2B ideas, largest TAM first
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/ideas?business_type=b2b&min_tam=1b&max_tam=50b&sort=tam"
# Full-text search, best match first
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/ideas?q=ai%20agents%20-crypto&min_attention=40"
# Solo-buildable software ideas with working unit economics, best-voted first
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/ideas?build_type=software&max_difficulty=2&min_ltv_cac=3&sort=votes"
# Fresh ideas on a theme, not yet deep-dived
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/ideas?theme=agentic&has_deep_dive=false&first_seen_since=2026-07-01T00:00:00Z"{
"data": [
{
"id": "002145db-0edb-4834-a191-27a3dda9a276",
"idea_code": "IDEA-042",
"name": "SettlementGlue — ERP Settlement Reconciliation Middleware",
"tagline": "Reconciles acquirer settlement files against ERP ledgers.",
"icp": "Merchant finance teams",
"problem": "Settlement receipts are disconnected from attribution pipelines.",
"solution": "Middleware that reconciles acquirer settlement files...",
"wedge": "Start with the top-3 acquirer formats.",
"project_thesis": "Payments complexity is compounding; finance teams...",
"business_type": "B2B",
"build_type": "Software",
"industry": "Fintech",
"status": "active",
"scores": {
"conviction": 81, // 0–100, or null
"timing": 5, // 1–5, or null
"asymmetry": 4, // 1–5, or null
"founder_market_fit": 3, // 1–5, or null
"severity": 5, // 1–5, or null
"market_growth": null, // 0–100, or null
"difficulty": 3 // 1–5 founder scale (1 solo … 5 VC-scale), or null
},
"attention": { "score": 62, "band": 3 }, // 0–100 / 1–5, or null
"financials": { // all number-or-null, USD unless noted
"tam_usd": 7000000000,
"sam_usd": 1500000000,
"som_usd": 50000000,
"cagr_5yr_pct": 22,
"growth_24mo_pct": 18,
"unit_margin_usd": 140000, // gross margin $/yr per customer
"cac_usd": 220000,
"customer_lifetime_years": 5,
"ltv_usd": 700000, // stored, else unit_margin × lifetime
"ltv_cac": 3.18,
"sources": { // per-field provenance; absent = agent-stated
"tam_usd": "estimate" // pack | estimate | manual
}
},
"surface": { "id": "SURF-019", "name": "SkillSign / TrustKit" },
"hypotheses": ["HYP-004", "HYP-020"], // thesis tags; filter with hypothesis=
"deep_dive": {
"id": "c4b3294c-...",
"verdict": "research", // pursue | research | deprioritize | null
"confidence": "65%"
},
"votes_7d": 0,
"votes_net": 2, // all-time net votes across members
"first_seen": "2026-06-16T21:00:00.000Z",
"last_updated": "2026-06-16T21:00:00.000Z",
"relevance": 0.83 // only present when q was given
}
],
"pagination": {
"limit": 50,
"offset": 0,
"count": 1,
"total": 464,
"has_more": true
}
}surface and deep_dive are null when an idea has none. financials.sources tells you where each number came from: pack (GTM research, most reliable), estimate (model backstop), or manual (operator-pinned). To page through everything, walk offset until has_more is false.
/api/public/v1/ideas/{id}Returns a single idea (the same shape as one element of data above), or 404 not_found.
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/ideas/002145db-0edb-4834-a191-27a3dda9a276"/api/public/v1/industriesThe vertical vocabulary behind /ideas?industry=… and each idea's industry field, with live active-idea counts — build filter chips from this instead of hard-coding labels. No parameters.
The industry filter is a substring match, so fintech, health, or devtools all work without the full label. Ideas not yet classified have industry: null and are excluded by any industry filter.
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/industries"{
"data": [
{ "industry": "Healthcare & Bio", "canonical": true, "active_ideas": 31 },
{ "industry": "Fintech", "canonical": true, "active_ideas": 54 },
{ "industry": "Security", "canonical": true, "active_ideas": 22 },
// ... all 13 canonical labels, even at zero; rare stray stored values
// append at the end with "canonical": false
],
"count": 13
}/api/public/v1/ideas/{id}/deep-diveReturns the idea's deep dive with its full founder-diligence pack — the 11 research markdown files (executive thesis, ICP, competitive analysis, pricing, GTM, demand tests, risks, …) plus the pitch-deck HTML, verdict, confidence, and venture economics. {id} accepts the idea UUID or its IDEA-### code.
source tells you whose pack it is: idea = generated for this exact idea; surface = inherited from the parent surface's newest pack (possibly researched for a sibling idea). If neither exists you get 404 no_deep_dive — the body carries the generation queue state, so after POSTing you can poll this same URL until the pack lands.
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/ideas/IDEA-042/deep-dive"{
"idea": { "id": "002145db-...", "idea_code": "IDEA-042", "name": "SettlementGlue" },
"deep_dive": {
"id": "c4b3294c-...",
"run_id": "8a1f5331-...",
"source": "idea", // idea | surface (see above)
"idea_id": "002145db-...", // null on surface-inherited packs
"surface": { "id": "SURF-019", "name": "SkillSign / TrustKit" },
"verdict": "research", // pursue | research | deprioritize | null
"confidence": "65%",
"headline_risk": "Buyers may not pay before a standard emerges.",
"economics": { "tam": "$7B", "som": "$50M", "revenue_m6": "$40k", ... },
"created_at": "2026-07-20T09:12:44.000Z",
"founder_diligence": [ // the pack's markdown files, verbatim
{ "filename": "00-executive-thesis.md", "content": "# ..." },
{ "filename": "01-ideal-customer-profile.md", "content": "# ..." },
// ... through 10-product-handoff.md
],
"pitch_deck_html": "<!doctype html>..." // or null
}
}pitch_deck_html is raw agent-authored HTML — if you embed it, do so only in a sandboxed iframe. Responses run large (hundreds of KB): fetch per idea on demand, don't bulk-poll this endpoint.
{
"error": "no_deep_dive",
"queue_status": "running", // queued | running | failed | null (never queued)
"runId": "d90c11f2-...", // the generating run, when one is attached
"generateUrl": "/api/public/v1/ideas/002145db-.../deep-dive"
}/api/public/v1/ideas/{id}/deep-diveGenerates the deep dive on demand — the same flow as the idea engine's Start Deep Dive: the idea is promoted into the Deep Dive Queue and a dedicated run starts immediately, running the GTM research agent on the idea's parent surface (idea injected as context) and then the validation agent (synthetic customers + customer intelligence). Returns 202 Accepted right away; the research takes tens of minutes. Poll statusUrl until the run completes, then fetch resultUrl. The request body is ignored.
This spends real research budget (premium model + web search), so it is deliberately conservative: it refuses if the idea already has its own pack (409 deep_dive_exists — GET it instead), if its generation is already underway (409 deep_dive_in_progress), or while any other run is in flight (409 run_in_progress — retry after it finishes). Ideas without a parent surface can't be researched: 422 no_parent_surface.
curl -X POST -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/ideas/IDEA-042/deep-dive"{
"runId": "d90c11f2-...",
"status": "pending",
"idea": { "id": "002145db-...", "idea_code": "IDEA-042", "name": "SettlementGlue" },
"statusUrl": "/api/public/v1/runs/d90c11f2-...",
"resultUrl": "/api/public/v1/ideas/002145db-.../deep-dive"
}/api/public/v1/runsStarts a full autonomous run end-to-end — sensing, synthesis, deep dives, and digest — with no human approval step. The run auto-selects its top surfaces and never pauses. Returns immediately; the work continues in the background. The request body is ignored.
Only one run executes at a time. If a run is already in flight, this returns 409 run_in_progress with the active run's id and status, and does not start a new one.
curl -X POST -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/runs"{
"runId": "8a1f5331-156c-41a0-bc28-509d96d0ee9e",
"status": "pending",
"statusUrl": "/api/public/v1/runs/8a1f5331-156c-41a0-bc28-509d96d0ee9e"
}{
"error": "run_in_progress",
"runId": "8a1f5331-...",
"status": "running"
}/api/public/v1/runs/{id}Poll a run's status using the statusUrl returned by the trigger. Poll every ~30–60s until status is terminal. Once available, the response also carries the run's digest markdown and a one-liner for each deep dive (deep_dives).
{
"runId": "8a1f5331-...",
"status": "completed",
"trigger_type": "api",
"started_at": "2026-06-17T14:53:06.823Z",
"completed_at": "2026-06-17T15:41:22.001Z",
"digest": "## This run...\n- ...", // run digest markdown, null until ready
"deep_dives": [ // one-liner per deep dive, [] until ready
{
"surface": "SkillSign / TrustKit",
"verdict": "research", // pursue | research | deprioritize | null
"confidence": "65%",
"headline_risk": "Buyers may not pay before a standard emerges."
}
]
}completed and failed are terminal; completed_at is set on success. Once a run is completed, fetch its output via GET /ideas?updated_since=<started_at>.
/api/public/v1/validationsLists synthetic customer validations (VAL-###) — for each researched idea, a 7-persona × 8-round synthetic focus group with a backend-computed customer-demand confidence (CDC). Use it as a second opinion beside the deep dive's own verdict (both are in each row), or to rank the shelf by validated demand.
| Parameter | Type | Default | Description |
|---|---|---|---|
| idea | string | — | Only validations of this idea (UUID or IDEA-###). |
| recommendation | enum | — | proceed | pivot | pause | kill. |
| status | enum | complete | complete | draft | quarantined | superseded | all. |
| min_cdc | 0–100 | — | Floor on the computed customer-demand confidence. |
| sort / order | enum | generated · desc | sort: generated | cdc. order: asc | desc. |
| limit / offset | int | 50 / 0 | Pagination (limit clamped 1–200). |
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/validations?recommendation=proceed&min_cdc=50&sort=cdc"{
"data": [
{
"id": "5b0c72a1-...",
"val_code": "VAL-024",
"version": "v1",
"status": "complete",
"recommendation": "pivot", // proceed | pivot | pause | kill
"central_unresolved_question": "Will mid-market finance teams trust ...?",
"cdc": { "score": 33.1, "band": "low", "delta": null }, // computed, never LLM-asserted
"idea": { "id": "002145db-...", "idea_code": "IDEA-042", "name": "SettlementGlue" },
"surface": { "id": "SURF-019", "name": "SkillSign / TrustKit" },
"pack_code": "PACK-017",
"deep_dive": { "verdict": "research", "confidence": "65%" }, // the GTM verdict, side by side
"personas_present": 7, // of the 7-persona manifest
"grounding_count": 6,
"run_id": "8a1f5331-...",
"generated_at": "2026-08-06T18:22:10.000Z"
}
],
"pagination": { "limit": 50, "offset": 0, "count": 1, "total": 24, "has_more": false }
}The CDC deliberately discounts synthetic evidence (×0.35), so low bands on unlaunched ideas are normal — it rises as real signals replace synthetic ones. Fetch the full transcript-level detail per idea via /ideas/{id}/validation.
/api/public/v1/ideas/{id}/validationThe idea's newest validation, fully expanded: the persona manifest (reusable as ad-audience hypotheses), the 8 focus-group rounds with the debate consensus, the 6 CDC inputs, cited demand-side grounding (real quotes and sources), the assumption backlog, and the marketing handoff — the exact probes (ICP segments, channels, messaging angles, pricing points, landing variants) the validation says to test with real traffic next. {id} accepts the idea UUID or IDEA-###.
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/ideas/IDEA-042/validation"{
"idea": { "id": "002145db-...", "idea_code": "IDEA-042", "name": "SettlementGlue" },
"validation": {
// ...all list fields above, plus:
"personas": [
{ "persona": "economic_buyer", "display_name": "Dana, VP Finance",
"role": "Controls the budget", "is_synthetic": true,
"present": true, "min_evidence_met": true },
// ... innovator | pragmatist | power_user | skeptic | competitor_user | non_customer
],
"rounds": [
{ "round_no": 1, "round": "problem_discovery", "is_debate": false,
"present": true, "personas_in_round": ["innovator","pragmatist"],
"consensus_score": null, "divergence_points": null,
"conclusion": "Pain is real but episodic..." },
// ... round 8 = structured_debate carries consensus_score + divergence_points
],
"cdc_inputs": [
{ "input": "pain_severity", "value_0_100": 62, "value_basis": "sourced",
"confidence": "medium", "evidence_ref": "G-3" }
// wtp_strength | persona_consensus | adoption_barrier_height | feature_value_clarity | wedge_resonance
],
"grounding": [
{ "claim": "Reconciliation threads recur weekly on r/accounting",
"url": "https://reddit.com/...", "source_name": "Reddit",
"source_type": "community", "source_tier": 2, "value_basis": "sourced",
"confidence": "medium", "as_of_date": "2026-07-30" }
],
"marketing_handoff": [
{ "probe_kind": "messaging_angle", "detail": "Lead with 'close the books 2 days faster'",
"resolves_assumption": "A2", "upgrades_input": "wtp_strength" }
],
"assumptions": [
{ "assumption_code": "A2", "category": "economic",
"impact_1_10": 8, "uncertainty_1_10": 7, "risk_score": 56 }
],
"lineage": [ { "kind": "hypothesis", "ref": "HYP-004" }, { "kind": "theme", "ref": "T012" } ]
}
}If the idea has no validation yet you get 404 no_validation with a generateUrl — validations mint on the deep-dive flow (POST the deep dive, then poll).
/api/public/v1/themesThe research themes behind the ideas, each with its latest computed state: evidence strength, supply/demand split, momentum, demand-vs-supply opportunity score, and change pressure. This is the "why now / still now?" layer — an idea whose theme is decaying carries timing risk its validation can't see. Ideas link to themes via their surface (/ideas?theme=…).
| Parameter | Type | Default | Description |
|---|---|---|---|
| lifecycle | enum | all | watchlist | tracked | dormant | merged | all. |
| q | string | — | Substring match on slug or name. |
| sort / order | enum | strength · desc | sort: strength | momentum | opportunity | demand | updated. order: asc | desc. |
| limit / offset | int | 50 / 0 | Pagination (limit clamped 1–200). |
# Where is demand outrunning supply right now?
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/themes?lifecycle=tracked&sort=opportunity"{
"data": [
{
"slug": "coding-agents-enterprise-scale",
"name": "Coding Agents at Enterprise Scale",
"description": "Autonomous coding agents moving from IDE toys to ...",
"layer": "application", // infrastructure | platform | application | unspecified
"lifecycle": "tracked", // watchlist | tracked | dormant | merged
"demand_native": false,
"first_seen_run": 3,
"latest": { // newest snapshot; null for never-scored themes
"run_index": 16,
"evidence_strength": 18.1, // 0–100, combined headline
"supply_strength": 3.8,
"demand_strength": 14.0,
"momentum": 2.4, // Δ vs prior run; null = baseline
"demand_momentum": 5.9,
"opportunity_score": 15.4, // demand-vs-supply gap, 0–100
"change_pressure": null, // −1..1, from the change-detection agent
"rank": 21,
"conviction": 3, // 1–5; team override wins over computed
"computed_at": "2026-08-06T18:03:58.060Z"
},
"updated_at": "2026-08-06T18:03:58.060Z"
}
],
"pagination": { "limit": 50, "offset": 0, "count": 1, "total": 21, "has_more": false }
}/api/public/v1/themes/{slug}One theme in depth: everything the list returns, plus history (the full snapshot time series, oldest first — plot it for the momentum/decay curve), and the theme's 25 most recent gaps, changes, and signals (same shapes as the corresponding list endpoints). Unknown slug → 404 not_found.
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/themes/coding-agents-enterprise-scale"/api/public/v1/boardThe unified Themes & Demand board: one row per theme carrying both the supply (Agent 1) and demand (Agent 2) sides of its latest computed state, signal counts, demand gaps, evidence-chain link counts, and the team's net vote. The richest single call for "what does the engine believe right now?" — where /themes is the thin list, this is the screener, with score-floor, categorical, and time filters. All filters combine with AND; total reflects the filtered set.
| Parameter | Type | Default | Description |
|---|---|---|---|
| min_strength / min_supply_strength / min_demand_strength / min_opportunity | number | — | Score floors (0–100) on the latest snapshot: combined evidence, supply, demand, and the demand-vs-supply opportunity score. |
| min_momentum | number | — | Momentum floor (−100–100); positive = strengthening since the prior run. |
| min_conviction | number | — | Conviction floor (1–5; team override wins over computed). |
| layer | enum | — | infrastructure | platform | application | unspecified. |
| lifecycle | enum | all | watchlist | tracked | dormant | merged | all. |
| origin_agent | enum | — | agent_1 (supply-first) | agent_2 (demand-first) — which agent minted the theme. |
| demand_native | bool | — | true = themes born from demand evidence rather than builder/funding supply. |
| run_index | int | — | Only themes whose latest snapshot is from exactly this run. |
| latest_run_only | bool | — | true = only themes scored in the most recent run (drops stale/dormant snapshots). |
| updated_since | ISO 8601 | — | Themes updated strictly after this timestamp. |
| first_seen_since | ISO 8601 | — | Themes first discovered on/after this date. |
| latest_signal_since | ISO 8601 | — | Themes with fresh evidence on/after this date. |
| q | string | — | Substring match on slug or name. |
| sort / order | enum | opportunity · desc | sort: opportunity | strength | supply | demand | momentum | demand_momentum | conviction | updated | latest_signal | found. order: asc | desc. |
| limit / offset | int | 50 / 0 | Pagination (limit clamped 1–200). |
# Tracked themes where demand is strong and evidence is fresh
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/board?lifecycle=tracked&min_demand_strength=40&latest_signal_since=2026-08-01&sort=opportunity"{
"as_of_run": 16, // most recent chain run index
"data": [
{
"slug": "agent-kill-switch-and-runtime-control",
"name": "Agent Kill-Switch and Runtime Control",
"description": "Runtime controls for stopping, constraining, ...",
"layer": "infrastructure",
"lifecycle": "watchlist",
"demand_native": false,
"origin_agent": "agent_1", // agent_1 | agent_2
"first_seen_run": 9,
"found_date": "2026-07-15", // date the theme first appeared
"updated_at": "2026-08-06T18:03:05.950Z",
"latest": { // newest snapshot; same shape as /themes
"run_index": 16,
"evidence_strength": 75.3,
"supply_strength": 39.1,
"demand_strength": 65.9,
"momentum": 0.9,
"demand_momentum": 0.9,
"opportunity_score": 33.2,
"change_pressure": null,
"rank": 1,
"conviction": 5,
"computed_at": "2026-08-06T18:03:58.067Z"
},
"supply_signal_count": 9, // all-time, Agent 1 side
"demand_signal_count": 26, // all-time, Agent 2 side
"runs_active": 8, // distinct runs that recorded a signal
"latest_signal_date": "2026-08-06", // freshest evidence
"active_opp_count": 3, // non-archived surfaces on this theme
"linked": { // evidence-chain counts (details via /ideas?theme=…)
"hypothesis_count": 5,
"surface_count": 3,
"idea_count": 49
},
"gaps": [ // latest gap-bearing run, max 10; same shape as /gaps
{
"gap_key": "GAP-2026-08-06-01",
"gap_type": "demand_gt_supply",
"strategic_implication": "Operators are encountering failures ...",
"confidence": "medium",
"demand_strength_at": 65.9,
"supply_strength_at": 39.1,
"gap_strength": 24.1
}
],
"vote": 2 // team net vote; null when none
}
],
"pagination": { "limit": 50, "offset": 0, "count": 1, "total": 12, "has_more": false }
}/api/public/v1/signalsThe atomic evidence behind the themes. Demand signals (class=demand) carry real user language — jobs-to-be-done, pain, frequency, willingness-to-pay — with the cited source URL: exactly the grounding landing copy and ad creative want instead of invented voice-of-customer. Supply signals are the builder/funding side.
| Parameter | Type | Default | Description |
|---|---|---|---|
| class | enum | — | supply | demand. Omit for both. |
| theme | string | — | Exact slug or theme-name substring. |
| disconfirming | bool | — | true = only bear-case / thesis-contradicting signals. |
| since | ISO 8601 | — | Only signals ingested strictly after this timestamp. |
| limit / offset | int | 50 / 0 | Pagination (limit clamped 1–200). |
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/signals?class=demand&theme=coding-agents"{
"data": [
{
"signal_key": "2026-08-06-017",
"theme": { "slug": "coding-agents-enterprise-scale", "name": "Coding Agents at Enterprise Scale" },
"class": "demand",
"claim": "Safe sandboxing and non-interactive MCP execution can conflict...",
"direction": "strengthen", // post-validation: strengthen | weaken | neutral | context_only
"magnitude": 2, // post-validation, 0–3
"is_disconfirming": false,
"published_date": "2026-08-04T00:00:00.000Z",
"source": {
"url": "https://forum.cursor.com/t/...",
"name": "Cursor Forum", "domain": "forum.cursor.com",
"type": "community", "tier": 1, // 1 best … 4; demand uses a per-signal effective tier
"from_harvest": true // the URL came from the harvest corpus
},
"demand_attributes": { // demand signals only; null for supply
"jtbd": "Run agents unattended without breaking security review",
"pain": "high", "frequency": "weekly", "wtp": "unknown",
"solution_gap": "no vendor covers both", "evidence_type": "forum_thread"
},
"notes": null,
"created_at": "2026-08-06T18:02:11.000Z"
}
],
"pagination": { "limit": 50, "offset": 0, "count": 1, "total": 160, "has_more": true }
}/api/public/v1/gapsSupply-vs-demand divergences (GAP-…): where customer demand outruns what's being built (or contradicts the thesis). Each gap carries the strengths on both sides at detection time and a computed gap_strength.
| Parameter | Type | Default | Description |
|---|---|---|---|
| gap_type | enum | — | demand_gt_supply | supply_gt_demand | demand_contradicts_thesis. |
| theme | string | — | Exact slug or theme-name substring. |
| min_strength | number ≥ 0 | — | Floor on gap_strength (quarantined gaps have null and are excluded). |
| since | ISO 8601 | — | Only gaps detected strictly after this timestamp. |
| sort / order | enum | created · desc | sort: created | strength. order: asc | desc. |
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/gaps?gap_type=demand_gt_supply&sort=strength"{
"data": [
{
"gap_key": "GAP-2026-07-09-02",
"theme": { "slug": "agentic-commerce", "name": "Agentic Commerce" },
"gap_type": "demand_gt_supply",
"strategic_implication": "Buyers are asking for agent-native checkout; few credible vendors.",
"confidence": "high", // low | medium | high
"is_disconfirming": false,
"demand_strength_at": 42.1,
"supply_strength_at": 7.3,
"gap_strength": 34.8, // null = quarantined
"created_at": "2026-07-09T03:14:22.000Z"
}
],
"pagination": { "limit": 50, "offset": 0, "count": 1, "total": 43, "has_more": false }
}/api/public/v1/harvestThe raw harvested corpus the sensing agents read: RSS/newsletter posts, HN threads, GitHub issue exhaust, app-store reviews, forum threads, funding filings, and more — titles + excerpts of real user language, newest first. Useful directly as copy/creative grounding when you want the source text itself rather than the distilled signal.
| Parameter | Type | Default | Description |
|---|---|---|---|
| source | enum | — | rss | hn | github | edgar | appstore | pkg | crypto | forum | gdelt | epoch | macro | ph. |
| category | string | — | Perspective lane / feed category (e.g. skeptic, emerging_vc). |
| site | string | — | Exact site key (case-insensitive), e.g. hn, a16z. |
| q | string | — | Substring match on title or excerpt. |
| since | ISO 8601 | — | Only items published strictly after this timestamp. |
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/harvest?source=forum&q=agent&since=2026-08-01T00:00:00Z"{
"data": [
{
"source": "forum",
"category": "forum",
"url": "https://forum.cursor.com/t/background-agents-timeout/...",
"title": "Background agents keep timing out on long refactors",
"excerpt": "Every time I hand the agent a multi-file refactor it dies at ...",
"site": "cursor-forum",
"author": "dev_ml",
"published_at": "2026-08-05T11:02:00.000Z",
"points": null, // HN only
"num_comments": 37,
"times_seen": 2,
"first_seen_at": "2026-08-05T12:00:04.000Z",
"last_seen_at": "2026-08-08T12:00:02.000Z"
}
],
"pagination": { "limit": 50, "offset": 0, "count": 1, "total": 454, "has_more": true }
}/api/public/v1/changesThe canonical change timeline (CHG-…): typed, material moves in theme or gap state — accelerations, decays, reversals, new-theme proposals — with magnitudes recomputed from the snapshot series (never model-asserted). Watch this to catch timing risk: an idea whose underlying theme shows decay events may have missed its window.
| Parameter | Type | Default | Description |
|---|---|---|---|
| theme | string | — | Exact slug or theme-name substring. |
| type | string | — | Post-validation change type, e.g. acceleration, decay, reversal. |
| min_magnitude | 0–100 | — | Floor on the recomputed materiality. |
| bar_cleared | bool | — | true = only events that cleared the materiality floor. |
| since | ISO 8601 | — | Only events created strictly after this timestamp. |
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/changes?theme=coding-agents&min_magnitude=25&bar_cleared=true"{
"data": [
{
"change_key": "CHG-2026-08-06-02",
"title": "Enterprise coding-agent demand accelerating",
"target_kind": "theme", // theme | gap
"theme": { "slug": "coding-agents-enterprise-scale", "name": "Coding Agents at Enterprise Scale" },
"gap_key": null, // set when target_kind = gap
"type": "acceleration", // post-validation type (use this)
"emitted_type": "acceleration", // as classified by the model
"confidence": "strong", // strong | moderate | emerging
"strategic_implication": "Window is opening; move surfaces on this theme up.",
"hypothesis_codes": ["HYP-004"],
"narrative_alignment": "confirms", // confirms | contradicts | ledger_leads | ledger_lags | mixed | not_checked
"raw_delta": 12.4, // signed Δ, recomputed from snapshots
"magnitude": 59.3, // 0–100 materiality, recomputed
"persistence_runs": 3,
"bar_cleared": true,
"run_index": 16,
"from_run_index": 15,
"created_at": "2026-08-06T18:05:41.000Z"
}
],
"pagination": { "limit": 50, "offset": 0, "count": 1, "total": 64, "has_more": true }
}/api/public/v1/hypothesesThe strategy ledger: the organization's core bets (7 by default;CORE-1..7) and the secondary hypotheses (HYP-###) with computed support scores and, per hypothesis, the ideas riding it — so a consumer can group the shelf by thesis instead of by score and triage a whole bet at once. Both tiers return in one unpaginated response (the ledger is small).
| Parameter | Type | Default | Description |
|---|---|---|---|
| lifecycle | enum | active | active | merged | retired | all. |
| status | string | — | Exact status (case-insensitive): Emerging, Strengthening, Stable, Weakening, Invalidated, ... |
| core | string | — | Only hypotheses mapped to this core bet (CORE-4; core-4 accepted). |
| min_support | 0–100 | — | Floor on the computed support score. |
| q | string | — | Substring match on the hypothesis statement. |
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/hypotheses?core=CORE-4&min_support=50"{
"core": [
{
"core_id": "CORE-1",
"position": 1,
"title": "Agents become the primary software interface",
"body": "Full prose of the core bet...",
"hypothesis_ids": ["HYP-003", "HYP-005", "HYP-012"], // active secondaries mapped here
"updated_at": "2026-07-28T10:00:00.000Z"
}
],
"data": [
{
"hyp_id": "HYP-004",
"statement": "Mid-market teams will pay for agent-native reconciliation...",
"category": "Demand",
"tier": "secondary", // core | secondary
"layer": "application",
"lifecycle": "active", // active | merged | retired | proposed_change_pending
"status": "Strengthening",
"timing_assessment": "Active Window",
"support": { "score": 68.5, "band": 4 }, // computed from evidence, canonical
"confidence": 4, // legacy asserted score
"evidence": { "for": 9, "against": 2 },
"maps_to_core": ["CORE-4", "CORE-5"],
"why_now": "...",
"what_must_be_true": "...",
"falsification_criteria": "...",
"strategic_implication": "...",
"idea_codes": ["IDEA-042", "IDEA-179", "IDEA-301"], // ideas riding this bet
"first_seen_run": 6,
"last_calibrated_run": 16,
"date_added": "2026-06-25T00:00:00.000Z",
"last_updated": "2026-08-06T00:00:00.000Z"
}
],
"count": 1
}idea_codes uses the same linkage as /ideas?hypothesis=… (direct pin + thesis tags + parent surface), so the two views stay consistent.
/api/public/v1/issuesThe Issue archive — the frozen Executive Overview brief minted after each completed run (twice weekly), newest first. Poll the list for a new issue_number to detect a fresh brief, then fetch it by number.
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/issues"{
"data": [
{ "issue_number": 15, "issue_date": "2026-08-06", "run_id": "8a1f5331-...",
"created_at": "2026-08-06T18:40:12.000Z" }
],
"pagination": { "limit": 50, "offset": 0, "count": 1, "total": 15, "has_more": false }
}/api/public/v1/issues/{number}One Issue. {number} is an issue number or latest. The default JSON carries dataset — the machine-readable brief (summary, themes + demand state, hypothesis scoreboard, pipeline, portfolio, VC signals) that rendered the page, ideal for an in-console market brief. Add ?format=html for the rendered self-contained document (a deterministic template render, not raw LLM HTML).
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/issues/latest"
# The rendered document
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://YOUR_HOST/api/public/v1/issues/latest?format=html" -o issue.htmlErrors
Errors are JSON with an error string (and sometimes extra fields). HTTP status carries the meaning.
| Status | Body | Meaning |
|---|---|---|
| 400 | {"error":"invalid_param","param":"…"} | A query parameter failed validation. |
| 401 | {"error":"unauthorized"} | Missing or incorrect bearer token. |
| 404 | {"error":"not_found"} | No idea or run with that id. |
| 404 | {"error":"no_deep_dive",…} | Idea exists but has no deep dive yet; body carries the queue state. |
| 404 | {"error":"no_validation",…} | Idea exists but has no synthetic validation yet; body carries the generateUrl. |
| 409 | {"error":"run_in_progress",…} | A run is already executing; trigger refused. |
| 409 | {"error":"deep_dive_exists",…} | The idea already has its own pack — GET it instead of regenerating. |
| 409 | {"error":"deep_dive_in_progress",…} | This idea's pack is already being generated. |
| 422 | {"error":"no_parent_surface"} | The idea has no parent surface, so nothing can be researched. |
| 503 | {"error":"api_not_configured"} | Server has no API key set — API disabled. |