Scan types
scanType is always explicit - there is no default. A refused deep scan is never silently downgraded to starter; it fails loudly (402 INSUFFICIENT_TOKENS or a service-disabled error).
While a deep run is still
PROCESSING, analysisTier reads basic until the deep sections land.
Use scanType (your request) as the in-flight signal and analysisTier as “is the deep result
ready yet”.Run lifecycle
readyForExport is separate from status: a run can be COMPLETED but still need enrichment before export. The enrich route skips whatever already exists, so calling it twice never regenerates or double-spends.
One exception: on a report created on the preuve.ai dashboard, readyForExport is always false and enrichment will not fix it. Those responses also carry exportable: false and exportBlockedCode: "REPORT_NOT_FROM_AGENT_RUN". Poll them here. For the data, relay exportBlockedHint: it names the way forward for that report, which may be the AI Context Pack on its report page (bundled on some plans, a purchase otherwise) or, when no pack is on offer for it, unlocking or re-running it there. Scan depth alone does not decide that, so do not infer it from scanType. A fresh deep analysis started here always works.
Partial enrichment failures return HTTP 207 with a success-shaped body and a failures list - retry by calling enrich again.
The ideas-json export (schemaVersion 2)
Every tier gets the summary contract:verdict,score,risk,quote,evidencedetails.verdict-{ score, label, narrative, keyInsight, recommendation, confidence }.labelcarries the same text asnarrative, kept for compatibilitydetails.market(TAM/SAM/SOM),details.competitors,details.swot,details.risks,details.validationdetails.quickTake,details.situationBriefing(string),details.actionPlanVariantsdetails.citations- deduped{ title, url }details.scores-compositeScoreplus per-framework subscoresdetails.cloneability- see below
details.cloneability
The one field whose shape changes with tier instead of going null. Branch on the fields you need rather than on tier: null means the run has no cloneability section at all, which is normal for analyses created before this field existed.
details.validation.featureTriage
Each entry is { feature, decision, status, impact, effort, reason }. decision normalizes the model’s free-text status to "build", "defer", "cut" or null; status is kept alongside so the original label stays readable.
Deep-only fields
details.sections- business model, execution fit, go-to-market, lean canvas, Porter forces, VC scorecard, PMF signals, financial projections, raise plan, pre-mortem, workflow evidence, display metrics, synthesis, consistency review, section briefings, Skeptic’s Viewdetails.marketextras -segments,industryTrends,competitivePositioning,geographicFocus,regulatoryLandscape(empty ornullon starter exports)- Full competitor cards - funding, estimated users, market share, activity level, threat level, scale tier and evidence, strengths, exploit tactics (starter exports keep
name+urlonly) details.pivots-{ suggestions, generatedAt }details.communityDemanddetails.founderFit,details.playbook,details.proofOfDemand,details.googleTrends- once the modules have been generated
null. Exports are deterministic: the same run state always serializes identically.
With verbosity=summary, details.sections keeps exactly one subsection, synthesis. Everything else in details.sections is dropped and listed under details.omitted.
Batches
POST /api/agent/analysis-batches accepts up to 5 items, each with its own clientRunId and scanType (mix starter and deep intentionally). The batch export includes only completed, export-ready items, plus omittedItems explaining every skipped item and aggregate counts.exported / counts.omitted.