ImprintPrivacyAPI & MCPTermsPricingFor fundsContactEN/

We use EU-hosted PostHog to understand product usage. No advertising or third-party marketing cookies. Essential login and session cookies work regardless of this choice. Privacy policy

SIMVC
Developersopenapi.json

On this page

  • Overview
  • Authentication
  • Walkthroughs
  • Webhooks
  • Schemas

account

  • get /me
  • get /openapi.json

decks

  • post /deck-check
  • post /decks
  • get /decks
  • get /decks/{deck_id}
  • delete /decks/{deck_id}

runs

  • post /runs
  • get /runs
  • get /runs/{run_id}
  • get /runs/{run_id}/report
  • get /runs/{run_id}/investors

drills

  • post /drills
  • get /runs/{run_id}/drills
  • get /drills/{drill_id}
  • post /drills/{drill_id}/message
  • post /drills/{drill_id}/end

flywheel

  • get /runs/{run_id}/calibrations
  • post /runs/{run_id}/calibrations
  • get /runs/{run_id}/miss-log
  • post /runs/{run_id}/miss-log
  • delete /miss-log/{miss_id}

intelligence

  • get /intelligence/cases
  • post /intelligence/cases
  • get /intelligence/cases/{case_id}
  • delete /intelligence/cases/{case_id}
  • post /intelligence/cases/{case_id}/pressure-test
  • post /intelligence/cases/{case_id}/reviews
API reference · 1.0.0-beta

SimVC API

Run SimVC's simulated-investor read of a pitch deck, or the fund-side pressure test, from your own workflow. Long-running work is a job: create, poll, read — or give a callback_url and be told once.

Limits. A pressure test, not a forecast. SimVC surfaces the objections and questions a deck creates in a simulated cohort of investors; it never computes or implies a probability of funding, and nothing in this response is a score to rank deals by.

Every string in a report comes from the same code path as the web app: named real investors and firms are scrubbed, and a quality auditor observes every artifact. Access is switched on per environment (SIMVC_API_ENABLED) and keys are minted in Settings → API keys.

Versioning. v1 is in beta. Additive changes — new fields, new routes, new error codes — ship without notice and never break a client that ignores fields it does not know. A rename or a removal only happens under a new base path (/api/v2), with both served for at least 90 days. Error codes are stable once documented. API changes are recorded in the project changelog under an API heading.

Rate limits. Every operation states its own limit (x-rate-limit), counted per key. Two runs may be active per account. A 429 carries rate_limited.

Base URL https://simvc.app/api/v1

Authentication

Authorization: Bearer sp_live_…

Minted in Settings → API keys. Shown once. Scopes: standard (decks, runs, reports, investors, flywheel, intelligence) and interview (adds drills).

Walkthroughs

Pressure-test a deal before IC

A fund analyst, from a CRM note or an assistant with the MCP server.

  1. 01

    Create the case from the deck and your thesis

    post /intelligence/cases

    Body
    {
      "name": "Acme — seed",
      "text": "…the deck's text…",
      "fund_thesis": "Vertical SaaS for mid-market logistics wins on data network effects.",
      "evaluation_criteria": "Retention ≥ 90% net; ≥ 3 paying design partners; founder-market fit.",
      "analyst_notes": "Churn slide looks selective.",
      "round_context": {
        "stage": "seed",
        "round_size": "€1.5M",
        "geography": "DACH"
      }
    }

    201 with the case in status: draft. Files are deleted after extraction. MCP: simvc_pressure_test does this step and the next in one call.

  2. 02

    Run the pressure test

    post /intelligence/cases/{case_id}/pressure-test

    The case comes back with report. Read report.summary.current_status — it belongs to the thesis, never to the company — and decision_hinges_on. There is no INVEST/HOLD/PASS and no score anywhere.

  3. 03

    Read the counter-thesis and the evidence gaps

    get /intelligence/cases/{case_id}

    counter_thesis is the centrepiece; evidence_gaps are ranked by decision impact; questions are the ones most likely to resolve the uncertainty (up to fifteen).

  4. 04

    Record what you found wrong, missing or useful

    post /intelligence/cases/{case_id}/reviews

    Body
    {
      "missed_concerns": "Customer concentration: two logos are 60% of ARR.",
      "changed_investigation": true,
      "saved_time_minutes": 45
    }

    Corrections improve the next test for this account only. MCP: simvc_record_correction.

A Reality Check from a founder tool

A deck builder or a founder's assistant, on the founder's own key.

  1. 01

    Upload the deck

    post /decks

    Body
    {
      "name": "Acme seed v3",
      "text": "…the deck's text…"
    }

    202 with ingest_status: processing; a PDF goes as multipart file. Poll the deck until ready. MCP: simvc_upload_deck, then simvc_wait_for_deck.

  2. 02

    Start the simulation with the fundraise frame

    post /runs

    Body
    {
      "deck_id": "{deck_id}",
      "cohort_size": 150,
      "frame": {
        "stage": "seed",
        "sector": "logistics",
        "business_model": "b2b_saas",
        "round_size": "€1.5M",
        "geography": "DACH",
        "lead_exists": false
      },
      "callback_url": "https://example.com/hooks/simvc"
    }

    201 with the run in status: pending. Runs spend the account's credits exactly as the app does. MCP: simvc_run_simulation, then simvc_wait_for_run.

  3. 03

    Wait: poll, or take the callback

    get /runs/{run_id}

    Every 15 seconds until status is complete or failed. With a callback_url, one signed POST arrives instead (see Webhooks).

  4. 04

    Read the report

    get /runs/{run_id}/report

    Read simulation_meta.rounds_run and collapsed before anything else. pass_reasons[].n_raised is how many simulated investors raised it — a distribution, not a probability. notice carries the limits sentence.

  5. 05

    Rehearse the top objection

    post /drills

    Body
    {
      "run_id": "{run_id}",
      "investor_id": "{investor_id}",
      "lang": "en"
    }

    Needs the interview scope. Pick the investor from /runs/{run_id}/investors. MCP: simvc_start_drill, simvc_drill_reply, simvc_end_drill.

account

get/mescope · anylimit · 60 per minute

Who am I

The account behind this key, its scope, credits, plan and today's spend against the cap. Call first.

Any scope.

Responses

200The account and key.
Example 200
{
  "account": {
    "id": "u-…",
    "email": "founder@acme.example",
    "name": "Ada",
    "email_verified": true
  },
  "key": {
    "id": "k-…",
    "label": "Claude Desktop",
    "key_prefix": "sp_live_4GFZ",
    "scope": "interview",
    "created_at": "2026-09-03T09:00:00",
    "last_used_at": "2026-09-03T10:11:00",
    "expires_at": null,
    "expired": false,
    "revoked": false
  },
  "credits": {
    "pool_enabled": true,
    "balance": 300,
    "trial_credits": 1
  },
  "entitlements": {
    "season_active": false,
    "season_expires_at": null,
    "prep_credits": 1
  },
  "spend_today": {
    "cents": 0,
    "cap_cents": 1500
  },
  "limits": {
    "active_runs": 2,
    "cohort_sizes": [
      30,
      150,
      300
    ]
  },
  "notice": "A pressure test, not a forecast. SimVC surfaces the objections and questions a deck creates in a simulated cohort of investors; it never computes or implies a probability of funding, and nothing in this response is a score to rank deals by."
}
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
get/openapi.jsonscope · limit · 60 per minute

This document

Responses

200The contract.

decks

post/deck-checkscope · anylimit · 30 per hour

Structural read of a deck

Which canonical sections are present, missing or out of order. One cheap call. JSON {"text": …} or multipart file. No simulation.

Any scope.

Request body

FieldTypeNotes
textstring
Example request
{
  "text": "Problem … Solution … Traction … Team … Ask …"
}

Responses

200The structural read.DeckCheck
Example 200
{
  "present": [
    "problem",
    "solution",
    "team",
    "round_ask"
  ],
  "missing_critical": [
    "traction",
    "business_model"
  ],
  "order_violations": [
    "team before problem"
  ]
}
400The request is malformed; error_code says how.Error
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
503Platform capacity for today is used up (daily_cap_reached: true).Error
post/decksscope · standardlimit · 30 per hour

Upload a deck

Multipart file (PDF, PPTX, ODP) with name, or JSON {"text": …, "name": …}. Ingest is asynchronous: answers 202 with ingest_status: processing; poll the deck until ready.

Scope: standard.

Request body

FieldTypeNotes
textstring
namestring
Example request
{
  "name": "Acme seed v3",
  "text": "Problem … Solution … Traction …"
}

Responses

202Accepted; ingesting.Deck
Example 202
{
  "id": "d1e2f3a4-…",
  "name": "Acme seed v3",
  "source_type": "text",
  "ingest_status": "processing",
  "fundraise_id": null,
  "version_number": 1,
  "created_at": "2026-09-03T10:10:00"
}
400The request is malformed; error_code says how.Error
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
413The upload exceeds the size cap.Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
get/decksscope · standardlimit · 60 per minute

List decks

This account's decks.

Scope: standard.

Responses

200Decks.
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
get/decks/{deck_id}scope · standardlimit · 60 per minute

Get a deck

Includes ingest_status.

Scope: standard.

Parameters

deck_id *path · stringThe deck's id.

Responses

200The deck.Deck
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
delete/decks/{deck_id}scope · standardlimit · 60 per minute

Delete a deck

Cascades to its runs exactly as the app does; a non-complete run refunds its credit.

Scope: standard.

Parameters

deck_id *path · stringThe deck's id.

Responses

200Deleted.Deleted
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error

runs

post/runsscope · standardlimit · 10 per hour

Create a simulation

Starts the cohort read as a job. callback_url is checked first, before any spend; then everything the app checks — deck ready, the active-run cap (two per account, 409 too_many_active_runs), credits or pass, today's caps, the global breaker.

Scope: standard.

Request body

FieldTypeNotes
deck_id *string
cohort_sizeinteger (30 | 150 | 300)A signal-stability parameter, not a target list. Default 150.
frameFrameThe fundraise frame the cohort is built for and the deck is judged against.
langstring (en | de) Default "en".
baseline_run_idstring | nullA completed run to compare against (delta).
forcebooleanRun even when the readiness check says the deck is thin. Default false.
callback_urlstring | null · uriPOSTed once on completion or failure with an X-SimVC-Signature: sha256=<hmac> header, keyed on the SHA-256 of your API key. Public hosts only.
Example request
{
  "deck_id": "{deck_id}",
  "cohort_size": 150,
  "frame": {
    "stage": "seed",
    "sector": "logistics",
    "business_model": "b2b_saas",
    "round_size": "€1.5M",
    "geography": "DACH",
    "lead_exists": false
  },
  "callback_url": "https://example.com/hooks/simvc"
}

Responses

201The run, status: pending.Run
Example 201
{
  "id": "9f1c2d3e-4b5a-4c6d-8e7f-0a1b2c3d4e5f",
  "deck_id": "d1e2f3a4-…",
  "status": "pending",
  "cohort_size": 150,
  "simulation_method": "heterogeneous-v2",
  "evaluation_mode": "fresh_room",
  "baseline_run_id": null,
  "evaluation_contract_version": "v3",
  "frame": {
    "stage": "seed",
    "sector": "logistics",
    "business_model": "b2b_saas",
    "round_size": "€1.5M",
    "geography": "DACH",
    "lead_exists": false
  },
  "error_message": null,
  "cost_euros": 0,
  "origin": "api",
  "callback_status": null,
  "started_at": null,
  "completed_at": null,
  "created_at": "2026-09-03T10:12:00",
  "message": "Simulation started — poll /api/simvc/runs/<id>"
}
400The request is malformed; error_code says how.Error
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
409A precondition is not met (for example deck_not_ready, too_many_active_runs).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
503Platform capacity for today is used up (daily_cap_reached: true).Error
get/runsscope · standardlimit · 60 per minute

List runs

This account's runs, newest first.

Scope: standard.

Responses

200Runs.
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
get/runs/{run_id}scope · standardlimit · 120 per minute

Get a run

Status and progress. Poll every 15 seconds, or use the callback.

Scope: standard.

Parameters

run_id *path · stringThe run's id.

Responses

200The run.Run
Example 200
{
  "id": "9f1c2d3e-4b5a-4c6d-8e7f-0a1b2c3d4e5f",
  "deck_id": "d1e2f3a4-…",
  "status": "running",
  "cohort_size": 150,
  "simulation_method": "heterogeneous-v2",
  "evaluation_mode": "fresh_room",
  "baseline_run_id": null,
  "evaluation_contract_version": "v3",
  "frame": {
    "stage": "seed",
    "sector": "logistics",
    "business_model": "b2b_saas",
    "round_size": "€1.5M",
    "geography": "DACH",
    "lead_exists": false
  },
  "error_message": null,
  "cost_euros": 0,
  "origin": "api",
  "callback_status": null,
  "started_at": "2026-09-03T10:12:05",
  "completed_at": null,
  "created_at": "2026-09-03T10:12:00",
  "message": "Simulation started — poll /api/simvc/runs/<id>",
  "deck_name": "Acme seed v3",
  "deck_version": 1,
  "fundraise_id": null
}
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
get/runs/{run_id}/reportscope · standardlimit · 60 per minute

Get the report

The report the app renders, gated by the same entitlement (a trial run returns the verdict and the top three reasons). 409 until the run is complete. ?lang=de for German when available.

Scope: standard.

Parameters

run_id *path · stringThe run's id.
langquery · string (en | de)

Responses

200The report.Report
Example 200
{
  "top_blocker": "demand is asserted, not evidenced",
  "pass_reasons": [
    {
      "rank": 1,
      "concern_key": "traction_quality",
      "n_raised": 61,
      "severity": "high",
      "honest_reason": "The traction slide shows sign-ups, not retained usage; nobody can tell whether anyone comes back.",
      "polite_version": "We'd love to see a bit more traction before we could get to conviction.",
      "archetypes": [
        "evidence-first operator",
        "metrics-led seed investor"
      ],
      "supporting_indices": [
        3,
        11,
        27
      ],
      "what_would_fix_it": "One cohort retention chart, month 1 to month 6."
    },
    {
      "rank": 2,
      "concern_key": "why_now",
      "n_raised": 34,
      "severity": "medium",
      "honest_reason": "Nothing on the deck says why this market opens now rather than in 2019.",
      "polite_version": "The timing question is one we'd want to dig into.",
      "archetypes": [
        "thesis-driven generalist"
      ],
      "supporting_indices": [
        5,
        8
      ],
      "what_would_fix_it": "A why-now slide with one regulatory or cost-curve fact."
    }
  ],
  "sources_of_conviction": [
    {
      "rank": 1,
      "strength": "A founder who ran the workflow being replaced, for six years.",
      "n_pulled_in": 42,
      "archetypes": [
        "founder-first angel"
      ],
      "evidence": "the team slide's operator background"
    }
  ],
  "diligence_dossier": [
    {
      "theme": "metrics",
      "questions": [
        {
          "q": "What is month-3 retention of the last three cohorts?",
          "n_asked": 58,
          "archetypes": [
            "evidence-first operator"
          ]
        }
      ]
    }
  ],
  "slide_feedback": [
    {
      "slide": 7,
      "n_stumbled": 40,
      "summary": "Sign-ups read as customers.",
      "fix": "Label the axis and add retained accounts."
    }
  ],
  "targeting_profile": "Operator-background seed investors who price on retention evidence; avoid momentum-led funds until a cohort chart exists.",
  "shortest_path_to_yes": {
    "fix": "Add one retention cohort chart.",
    "unlocks": "several who stopped at a soft pass moving toward a first meeting"
  },
  "simulation_meta": {
    "rounds_run": [
      0,
      1,
      2
    ],
    "rounds_skipped": [],
    "collapsed": false,
    "round0_distribution": {
      "HARD_PASS": 71,
      "SOFT_PASS": 46,
      "WATCHLIST": 25,
      "FIRST_MEETING": 8
    }
  },
  "frame_check": {
    "stage": "seed",
    "bar": "seed"
  },
  "benchmarks_used": [],
  "notice": "A pressure test, not a forecast. SimVC surfaces the objections and questions a deck creates in a simulated cohort of investors; it never computes or implies a probability of funding, and nothing in this response is a score to rank deals by."
}
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
409A precondition is not met (for example deck_not_ready, too_many_active_runs).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
get/runs/{run_id}/investorsscope · standardlimit · 60 per minute

List simulated investors

Every profile with its honest and polite pass line, questions and slide stumbles, most sceptical first. ?state= filters by stance.

Scope: standard.

Parameters

run_id *path · stringThe run's id.
statequery · string

Responses

200The cohort.Investors
Example 200
{
  "count": 2,
  "invalid_assessments": 0,
  "concern_clusters": [],
  "investors": [
    {
      "id": "inv-…",
      "archetype": "evidence-first operator",
      "cohort_fit": "core",
      "state": "HARD_PASS",
      "conviction": 0.12,
      "honest_reason": "Sign-ups are not customers, and the deck cannot tell them apart.",
      "polite_version": "Too early for us — keep us posted on traction.",
      "what_pulled_me_in": null,
      "questions": [
        "What is month-3 retention?"
      ],
      "slide_stumbles": [
        {
          "slide": 7,
          "issue": "sign-ups read as customers"
        }
      ]
    },
    {
      "id": "inv-…",
      "archetype": "founder-first angel",
      "cohort_fit": "core",
      "state": "WATCHLIST",
      "conviction": 0.58,
      "honest_reason": "I believe the founder; I do not yet believe the market timing.",
      "polite_version": "Would love to stay close as this develops.",
      "what_pulled_me_in": "six years running the replaced workflow",
      "questions": [
        "Why now, in one sentence?"
      ],
      "slide_stumbles": []
    }
  ]
}
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
409A precondition is not met (for example deck_not_ready, too_many_active_runs).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error

drills

post/drillsscope · interviewlimit · 30 per hour

Open a drill

Rehearse against one investor's actual objection (or a panel of two or three). Ten drills per run.

Scope: interview.

Request body

FieldTypeNotes
run_id *string
investor_idstringSolo drill against one profile.
investor_idsarray<string>Panel drill against two or three.
langstring (en | de) Default "en".
Example request
{
  "run_id": "9f1c…",
  "investor_id": "inv-…",
  "lang": "en"
}

Responses

201The drill with its opener.Drill
Example 201
{
  "id": "dr-…",
  "run_id": "9f1c…",
  "investor_id": "inv-…",
  "status": "active",
  "mode": "solo",
  "lang": "en",
  "transcript": [
    {
      "role": "investor",
      "text": "Walk me through slide 7 — are those customers or sign-ups?"
    }
  ],
  "investors": [
    {
      "id": "inv-…",
      "archetype": "evidence-first operator"
    }
  ]
}
400The request is malformed; error_code says how.Error
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
409A precondition is not met (for example deck_not_ready, too_many_active_runs).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
503Platform capacity for today is used up (daily_cap_reached: true).Error
get/runs/{run_id}/drillsscope · interviewlimit · 60 per minute

List drills

The run's drills.

Scope: interview.

Parameters

run_id *path · stringThe run's id.

Responses

200Drills.Drills
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
get/drills/{drill_id}scope · interviewlimit · 120 per minute

Get a drill

Transcript so far.

Scope: interview.

Parameters

drill_id *path · stringThe drill's id.

Responses

200The drill.Drill
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
post/drills/{drill_id}/messagescope · interviewlimit · 120 per hour

Send a turn

Your answer; the investor replies in character.

Scope: interview.

Parameters

drill_id *path · stringThe drill's id.

Request body

FieldTypeNotes
message *string

Responses

200The investor's reply and the drill state.Drill
400The request is malformed; error_code says how.Error
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
409A precondition is not met (for example deck_not_ready, too_many_active_runs).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
503Platform capacity for today is used up (daily_cap_reached: true).Error
post/drills/{drill_id}/endscope · interviewlimit · 60 per hour

End a drill

Closes it with the investor's debrief.

Scope: interview.

Parameters

drill_id *path · stringThe drill's id.

Responses

200The closed drill.Drill
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error

flywheel

get/runs/{run_id}/calibrationsscope · standardlimit · 60 per minute

List calibrations

Labels this account gave on the run.

Scope: standard.

Parameters

run_id *path · stringThe run's id.

Responses

200Calibrations.Calibrations
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
post/runs/{run_id}/calibrationsscope · standardlimit · 120 per hour

Label an item

"Were you asked this in a real meeting?" — recorded against the run. This is how the simulation learns.

Scope: standard.

Parameters

run_id *path · stringThe run's id.

Request body

"Were you asked this in a real meeting?" — the flywheel.

FieldTypeNotes
item_typestring (question | pass_reason)
item_textstring
labelboolean | nulltrue = it happened, false = it did not, null clears.

Responses

200Recorded.CalibrationResult
400The request is malformed; error_code says how.Error
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
get/runs/{run_id}/miss-logscope · standardlimit · 60 per minute

List misses

What real meetings raised that the simulation did not.

Scope: standard.

Parameters

run_id *path · stringThe run's id.

Responses

200Misses.Misses
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
post/runs/{run_id}/miss-logscope · standardlimit · 120 per hour

Record a miss

A question or objection the simulation missed.

Scope: standard.

Parameters

run_id *path · stringThe run's id.

Request body

FieldTypeNotes
item_typestring (question | objection) Default "question".
text *string
archetype_guessstring | null

Responses

201Recorded.MissResult
400The request is malformed; error_code says how.Error
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
delete/miss-log/{miss_id}scope · standardlimit · 60 per hour

Delete a miss

Scope: standard.

Parameters

miss_id *path · stringThe miss's id.

Responses

200Deleted.
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error

intelligence

get/intelligence/casesscope · standardlimit · 60 per minute

List cases

This account's pressure-test cases. The intelligence pilot has its own flag and allowlist; 404 when it is off for this environment or account.

Scope: standard.

Responses

200Cases.
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
post/intelligence/casesscope · standardlimit · 30 per hour

Create a case

Deck (text or file) plus the fund's thesis and evaluation criteria, optional analyst notes and round context.

Scope: standard.

Request body

JSON with text, or multipart with file (PDF, PPTX, ODP). Files are deleted after extraction.

FieldTypeNotes
namestring
textstringPasted deck text (JSON body).
fund_thesis *string
evaluation_criteria *string
analyst_notesstring
round_contextobject
stagestring
round_sizestring
geographystring
sectorstring
business_modelstring
cheque_rangestring
ownership_targetstring
Example request
{
  "name": "Acme — seed",
  "text": "…the deck's text…",
  "fund_thesis": "Vertical SaaS for mid-market logistics wins on data network effects.",
  "evaluation_criteria": "Retention ≥ 90% net; ≥ 3 paying design partners; founder-market fit.",
  "analyst_notes": "Churn slide looks selective.",
  "round_context": {
    "stage": "seed",
    "round_size": "€1.5M",
    "geography": "DACH"
  }
}

Responses

201The case, status: draft.Case
Example 201
{
  "id": "c0a1b2c3-…",
  "name": "Acme — seed",
  "status": "draft",
  "source_type": "text",
  "source_filename": null,
  "origin": "api",
  "prompt_version": "pt-3",
  "cost_euros": 0.06,
  "round_context": {
    "stage": "seed",
    "round_size": "€1.5M",
    "geography": "DACH"
  },
  "created_at": "2026-09-03T10:20:00",
  "reviews": [],
  "report": null
}
400The request is malformed; error_code says how.Error
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
get/intelligence/cases/{case_id}scope · standardlimit · 60 per minute

Get a case

With its report when complete.

Scope: standard.

Parameters

case_id *path · stringThe intelligence case's id.

Responses

200The case.Case
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
delete/intelligence/cases/{case_id}scope · standardlimit · 60 per minute

Delete a case

Removes the extracted material, the report and the reviews.

Scope: standard.

Parameters

case_id *path · stringThe intelligence case's id.

Responses

200Deleted.Deleted
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
post/intelligence/cases/{case_id}/pressure-testscope · standardlimit · 10 per day

Run the pressure test

One bounded generation. Synchronous today: the response carries the completed case. {"force": true} re-runs a complete case.

Scope: standard.

Parameters

case_id *path · stringThe intelligence case's id.

Request body

FieldTypeNotes
forceboolean
Example request
{}

Responses

200The case with its report.Case
Example 200
{
  "id": "c0a1b2c3-…",
  "name": "Acme — seed",
  "status": "complete",
  "source_type": "text",
  "source_filename": null,
  "origin": "api",
  "prompt_version": "pt-3",
  "cost_euros": 0.06,
  "round_context": {
    "stage": "seed",
    "round_size": "€1.5M",
    "geography": "DACH"
  },
  "created_at": "2026-09-03T10:20:00",
  "completed_at": "2026-09-03T10:20:41",
  "report": {
    "summary": {
      "current_status": "PLAUSIBLE — INSUFFICIENT EVIDENCE",
      "decision_hinges_on": [
        "retention quality",
        "customer concentration",
        "competitive differentiation"
      ]
    },
    "thesis": {
      "claim": "Vertical SaaS for mid-market logistics wins on data network effects.",
      "support": [
        "three design partners",
        "operator founder"
      ]
    },
    "counter_thesis": {
      "claim": "Apparent leadership reflects an immature category, not a durable advantage.",
      "support": [
        "no competitive win/loss data supplied"
      ]
    },
    "evidence_gaps": [
      {
        "gap": "retention by cohort",
        "decision_impact": "high",
        "source": "traction slide (7)"
      }
    ],
    "contradictions": [
      {
        "claim": "90% retention",
        "conflicts_with": "sign-up counts on slide 7",
        "source": "slides 4, 7"
      }
    ],
    "disagreement_map": [
      {
        "topic": "market timing",
        "positions": [
          "opens now",
          "opened in 2019"
        ]
      }
    ],
    "decision_conditions": [
      {
        "claim": "category leadership",
        "must_be_true": "attributable competitive wins the company can keep"
      }
    ],
    "questions": [
      {
        "q": "Which customers evaluated you against a named alternative, and why did they choose you?",
        "resolves": "competitive differentiation"
      }
    ]
  },
  "reviews": []
}
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
409A precondition is not met (for example deck_not_ready, too_many_active_runs).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error
503Platform capacity for today is used up (daily_cap_reached: true).Error
post/intelligence/cases/{case_id}/reviewsscope · standardlimit · 30 per hour

Record a correction

What the analyst found wrong, missing or useful, and the time it saved. Improves the next test for this account only.

Scope: standard.

Parameters

case_id *path · stringThe intelligence case's id.

Request body

Analyst corrections — the product's learning loop. The response is the recorded review, with id and created_at.

FieldTypeNotes
idstring
created_atstring | null · date-time
new_findingsstring
improved_questionsstring
wrong_or_distractingstring
missed_concernsstring
changed_investigationboolean
saved_time_minutesinteger
Example request
{
  "missed_concerns": "Customer concentration: two logos are 60% of ARR.",
  "changed_investigation": true,
  "saved_time_minutes": 45
}

Responses

201The recorded review.Review
Example 201
{
  "id": "rv-…",
  "created_at": "2026-09-03T10:31:00",
  "missed_concerns": "Customer concentration: two logos are 60% of ARR.",
  "changed_investigation": true,
  "saved_time_minutes": 45
}
400The request is malformed; error_code says how.Error
401Missing, revoked, expired or unknown API key.Error
Example 401
{
  "error": "Invalid or missing API key",
  "error_code": "unauthorized"
}
403The key lacks the scope this route needs, the object belongs to another account, or the account is not allowed.Error
404Not found, or API access is off (api_disabled).Error
409A precondition is not met (for example deck_not_ready, too_many_active_runs).Error
429Rate limit (rate_limited), or today's account capacity (account_cap_reached: true).Error

Webhooks

Run completion callback

Sent once to callback_url, on completion or failure, with up to three attempts. Reply 2xx. Verify the signature before trusting the body.

X-SimVC-Eventrun.completed | run.failed
X-SimVC-Runthe run id
X-SimVC-Signaturesha256=<hex> — HMAC-SHA256(key = SHA-256(your API key) as hex, message = the raw body)
User-AgentSimVC-Callback/1

Body

The body POSTed to callback_url. A pointer, never the report. Verify X-SimVC-Signature = sha256= + HMAC-SHA256(key=SHA-256(your API key), body).

FieldTypeNotes
eventstring (run.completed | run.failed)
run_idstring
deck_idstring
statusstring
cohort_sizeinteger
completed_atstring | null · date-time
error_messagestring | null
report_pathstring
run_pathstring
Example body
{
  "event": "run.completed",
  "run_id": "9f1c…",
  "deck_id": "d1e2f3a4-…",
  "status": "complete",
  "cohort_size": 150,
  "completed_at": "2026-09-03T10:19:40",
  "error_message": null,
  "report_path": "/api/v1/runs/9f1c…/report",
  "run_path": "/api/v1/runs/9f1c…"
}

Schemas

Error

Every non-2xx answer. error is always present. error_code is present for the refusals this API and the product name explicitly; a few product refusals carry a boolean flag instead.

FieldTypeNotes
error *stringHuman-readable message.
error_codestringStable machine code. From /api/v1: api_disabled, unauthorized, insufficient_scope, rate_limited, invalid_callback_url, too_many_active_runs. From the product: deck_not_ready, deck_source_missing, unsupported_deck_format, company_name_required, fundraise_label_required, fundraise_attachment_conflict, unchanged_deck_source, unchanged_revision_source, deck_history_changed, deck_history_not_repairable, purchase_required, invalid_baseline_cohort_size, incompatible_replay_baseline, cross_fundraise_baseline, checkout_unavailable, checkout_session_failed, checkout_credentials_rejected. Not exhaustive: the product may add codes.
payment_requiredbooleanSet on that refusal instead of an error_code.
daily_cap_reachedbooleanSet on that refusal instead of an error_code.
account_cap_reachedbooleanSet on that refusal instead of an error_code.

Frame

The fundraise frame the cohort is built for and the deck is judged against.

FieldTypeNotes
stagestring (business-angel | pre-seed | seed | series-a | series-b | series-c | growth)
round_sizestring
geographystring
sectorstring
business_modelstring (b2b_saas | marketplace | deep_tech | consumer | other)
traction_bandstring
lead_existsboolean

Deck

FieldTypeNotes
idstring
namestring
source_typestring (pdf | pptx | odp | text)
ingest_statusstring (processing | ready | failed)A run may start only at ready.
fundraise_idstring | null
version_numberinteger | null
created_atstring · date-time

DeckCheck

Structural read only: which canonical sections are present, missing or out of order. No simulation, no pass reasons.

FieldTypeNotes
presentarray<string>
missing_criticalarray<string>
order_violationsarray<string>

RunCreate

FieldTypeNotes
deck_id *string
cohort_sizeinteger (30 | 150 | 300)A signal-stability parameter, not a target list. Default 150.
frameFrameThe fundraise frame the cohort is built for and the deck is judged against.
langstring (en | de) Default "en".
baseline_run_idstring | nullA completed run to compare against (delta).
forcebooleanRun even when the readiness check says the deck is thin. Default false.
callback_urlstring | null · uriPOSTed once on completion or failure with an X-SimVC-Signature: sha256=<hmac> header, keyed on the SHA-256 of your API key. Public hosts only.

Run

FieldTypeNotes
idstring
deck_idstring
statusstring (pending | running | complete | failed)
cohort_sizeinteger
frameFrameThe fundraise frame the cohort is built for and the deck is judged against.
originstring (web | api)
callback_statusstring | null (delivered | failed | skipped | null)
error_messagestring | null
started_atstring | null · date-time
completed_atstring | null · date-time
created_atstring · date-time

PassReason

One recurring reason the simulated cohort passed, in distribution language.

FieldTypeNotes
rankintegerPosition in this list, by how many raised it. An ordinal, not a score.
concern_keystring
honest_reasonstring
polite_versionstringThe email version founders recognise from their inbox.
n_raisedintegerHow many simulated investors raised it.
severitystring (high | medium | low)
archetypesarray<string>Psychologies, never people or firms.
what_would_fix_itstring

SourceOfConviction

FieldTypeNotes
rankinteger
strengthstring
n_pulled_ininteger
archetypesarray<string>
evidencestring

SimulationMeta

Read this before drawing any conclusion: rounds 1 and 2 are conditional.

FieldTypeNotes
rounds_runarray<integer>
rounds_skippedarray<integer>
collapsedboolean
round0_distributionobjectCounts per stance in the cold read. A distribution of a simulated cohort — not a probability of anything.

Report

FieldTypeNotes
top_blockerstring
pass_reasonsarray<PassReason>
sources_of_convictionarray<SourceOfConviction>
diligence_dossierarray<object>
slide_feedbackarray<object>
targeting_profilestringWhat kind of investor to prioritise. Never names.
shortest_path_to_yesobject
simulation_metaSimulationMetaRead this before drawing any conclusion: rounds 1 and 2 are conditional.
frame_checkobject
benchmarks_usedarray<object>
gatedbooleanTrue on a trial run: verdict and the top three reasons only.
noticestringA pressure test, not a forecast. SimVC surfaces the objections and questions a deck creates in a simulated cohort of investors; it never computes or implies a probability of funding, and nothing in this response is a score to rank deals by.

Investors

The run's simulated cohort, most sceptical first (at most 400).

FieldTypeNotes
countinteger
investorsarray<Investor>
invalid_assessmentsintegerProfiles whose assessment failed the evaluation contract and were withheld.
concern_clustersarray<object>

Investor

A simulated profile. An archetype with its own mandate, evidence threshold and pass logic — not a person.

FieldTypeNotes
idstring
archetypestring
cohort_fitstring
statestring (HARD_PASS | SOFT_PASS | WATCHLIST | FIRST_MEETING)
honest_reasonstring
polite_versionstring
what_pulled_me_instring | null
questionsarray<string>
slide_stumblesarray<object>

DrillCreate

FieldTypeNotes
run_id *string
investor_idstringSolo drill against one profile.
investor_idsarray<string>Panel drill against two or three.
langstring (en | de) Default "en".

Drill

FieldTypeNotes
idstring
run_idstring
statusstring (active | complete)
modestring (solo | panel)
langstring
messagesarray<object>

Calibration

"Were you asked this in a real meeting?" — the flywheel.

FieldTypeNotes
item_typestring (question | pass_reason)
item_textstring
labelboolean | nulltrue = it happened, false = it did not, null clears.

CalibrationResult

FieldTypeNotes
okboolean
labelboolean | null
credit_grantedbooleanThe calibration credit, once per run.

Calibrations

FieldTypeNotes
calibrationsarray<object>

Miss

What the simulation missed that a real meeting raised.

FieldTypeNotes
idstring
item_typestring (question | objection)
textstring
archetype_guessstring | null
created_atstring | null · date-time

MissCreate

FieldTypeNotes
item_typestring (question | objection) Default "question".
text *string
archetype_guessstring | null

MissResult

FieldTypeNotes
missMissWhat the simulation missed that a real meeting raised.
credit_grantedboolean

Misses

FieldTypeNotes
missesarray<Miss>

Drills

FieldTypeNotes
drillsarray<Drill>

Deleted

FieldTypeNotes
deletedboolean

CaseCreate

JSON with text, or multipart with file (PDF, PPTX, ODP). Files are deleted after extraction.

FieldTypeNotes
namestring
textstringPasted deck text (JSON body).
fund_thesis *string
evaluation_criteria *string
analyst_notesstring
round_contextobject
stagestring
round_sizestring
geographystring
sectorstring
business_modelstring
cheque_rangestring
ownership_targetstring

Case

The pressure test: thesis, counter-thesis, evidence gaps, contradictions, disagreement map, decision conditions, up to 15 resolving questions. The status belongs to the thesis, never to the company. No INVEST/HOLD/PASS.

FieldTypeNotes
idstring
namestring
statusstring (draft | running | complete | failed)
originstring | null
reportobject | null

Review

Analyst corrections — the product's learning loop. The response is the recorded review, with id and created_at.

FieldTypeNotes
idstring
created_atstring | null · date-time
new_findingsstring
improved_questionsstring
wrong_or_distractingstring
missed_concernsstring
changed_investigationboolean
saved_time_minutesinteger

Callback

The body POSTed to callback_url. A pointer, never the report. Verify X-SimVC-Signature = sha256= + HMAC-SHA256(key=SHA-256(your API key), body).

FieldTypeNotes
eventstring (run.completed | run.failed)
run_idstring
deck_idstring
statusstring
cohort_sizeinteger
completed_atstring | null · date-time
error_messagestring | null
report_pathstring
run_pathstring

A pressure test, not a forecast. SimVC surfaces the objections and questions a deck creates in a simulated cohort of investors; it never computes or implies a probability of funding, and nothing in this response is a score to rank deals by.