Skip to main content

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, evidence
  • details.verdict - { score, label, narrative, keyInsight, recommendation, confidence }. label carries the same text as narrative, kept for compatibility
  • details.market (TAM/SAM/SOM), details.competitors, details.swot, details.risks, details.validation
  • details.quickTake, details.situationBriefing (string), details.actionPlanVariants
  • details.citations - deduped { title, url }
  • details.scores - compositeScore plus per-framework subscores
  • details.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 View
  • details.market extras - segments, industryTrends, competitivePositioning, geographicFocus, regulatoryLandscape (empty or null on 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 + url only)
  • details.pivots - { suggestions, generatedAt }
  • details.communityDemand
  • details.founderFit, details.playbook, details.proofOfDemand, details.googleTrends - once the modules have been generated
On starter runs all deep-only fields are 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.