> ## Documentation Index
> Fetch the complete documentation index at: https://docs.originalis.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Analyze a founder

> Run an Originalis founder assessment.

Deduped per org: if your org already assessed this founder (or a run
is in flight), you get the existing analysis back with
`existing: true` — no new run is started or billed. Otherwise the
research-agent pipeline runs asynchronously (typically minutes);
poll `status_url`.

Requires a write-scoped API key and draws down the daily actions
budget.



## OpenAPI

````yaml https://api.originalis.ai/api/v1/openapi.json?v=1-10-0-summaries post /api/v1/founders/analyze
openapi: 3.1.0
info:
  title: Originalis Public API
  description: >-
    Programmatic access to your firm's Originalis workspace — the deal pipeline,
    portfolio book, LP fund positions, and the network intelligence your team's
    own emails and calendars actually evidence.


    One API key, one base URL, plain JSON. Every `GET` is a pure read; the only
    endpoints that change anything are the explicit `POST` **actions**
    (analysis, research) and webhook management — write-scoped, budgeted, and
    documented below.


    ## What you can query


    | Capability | Endpoint | Typical use |

    | --- | --- | --- |

    | Who do we know at X | `GET /api/v1/network/who-knows` | Warm-intro
    sourcing: ranked paths to a company or person, each naming the teammate who
    owns the relationship |

    | Warmth lookup | `POST /api/v1/network/warmth/lookup` | CRM enrichment:
    send up to 100 emails / contact ids, get relationship warmth back |

    | Contact export | `GET /api/v1/network/contacts` | Sync your graph (with
    warmth) into a CRM or warehouse, one cursor-paginated sweep |

    | Reach candidates | `GET /api/v1/network/reach/candidates` | Precomputed
    proxy-first-degree candidates from background fan-out runs |

    | Relationship signals | `GET /api/v1/network/signals/going-stale` |
    Relationships drifting past their touch cadence |

    | Deal pipeline | `GET /api/v1/deals` | Sync your org's deal workspace
    (status, stage, score) into a CRM or warehouse |

    | Deal detail | `GET /api/v1/deals/{deal_id}` | Structured record for one
    deal: company facts, round, team, score |

    | **Analyze a deal** | `POST /api/v1/deals/analyze` | Submit a company/fund
    website — or a DocSend/Notion/Drive/Canva/Figma/Gamma/Dropbox document link;
    full analysis runs async into your workspace |

    | **Analyze an uploaded file** | `POST /api/v1/deals/analyze/upload` |
    Multipart upload a deck (PDF/PPT/DOC) and run the full analysis on it |

    | **Add data-room documents** | `POST /api/v1/deals/{deal_id}/documents` |
    Push diligence files into a deal's data room; they're classified + analyzed
    async |

    | Deal documents | `GET /api/v1/deals/{deal_id}/documents` | The deal's
    document inventory: primary uploads + data-room files with folders |

    | Analysis status | `GET /api/v1/deals/{deal_id}/analysis` | Poll a
    submitted analysis: queued → running → succeeded/failed |

    | **Analyze a founder** | `POST /api/v1/founders/analyze` | Run a founder
    assessment from a name / LinkedIn / GitHub; org-deduped |

    | Founder analysis | `GET /api/v1/founders/analyses/{analysis_id}` | Status
    + the finished assessment: scores, strengths, risks, research |

    | **Run research** | `POST /api/v1/research` | Submit a question; a
    deep-research run produces a cited Markdown report |

    | Research report | `GET /api/v1/research/{research_id}` | Status + the
    finished report with citations |

    | Portfolio book | `GET /api/v1/portfolio/companies` | Holdings with ledger
    economics + latest operating metrics, for warehouse sync |

    | Metric history | `GET /api/v1/portfolio/companies/{company_id}/metrics` |
    Dated history of one metric for one holding (ARR trajectory, burn trend) |

    | LP positions | `GET /api/v1/funds/positions` | Fund commitments with
    called/distributed/NAV, TVPI/DPI, and data-quality flags |

    | LP cashflows | `GET /api/v1/funds/cashflows` | The dated call/distribution
    ledger, for reconciliation |

    | LP mark history | `GET /api/v1/funds/marks` | Each commitment's dated
    NAV/TVPI trace — the momentum view |

    | **Webhooks** | `POST /api/v1/webhooks` | Register a signed-event endpoint;
    list, delete, and inspect deliveries |


    ## Getting started


    Three steps to a first call:


    **1 — Mint a key.** In the Originalis app, go to [Integrations → API
    Keys](https://app.originalis.ai/app/integrations/api-keys) and create a key.
    The secret (`ak_...`) is shown once — store it in your secret manager. Keys
    can be given an expiry and revoked at any time.


    **2 — Call the API.**


    ```bash

    curl -H "Authorization: Bearer ak_..." \
      "https://api.originalis.ai/api/v1/network/who-knows?domain=acme.com"
    ```


    **3 — Read the response.** Responses are plain JSON; list and detail

    reads state their `scope` (whose data you're seeing) and carry `as_of`:


    ```json

    {
      "target": { "domain": "acme.com", "person": null },
      "scope": "org_shared",
      "paths": [
        {
          "contact_id": "9f2c1b7a-4e11-4c2e-9b3a-1d5f6a7b8c9d",
          "name": "Jane Doe",
          "title": "CTO",
          "email": "jane@acme.com",
          "warmth": 0.72,
          "strength_score": 81.0,
          "relationship": "strong",
          "path_owner": "Mark Smith"
        }
      ],
      "unavailable_reason": null,
      "as_of": "2026-09-02T14:00:00Z"
    }

    ```


    ## Authentication


    Every request needs an Originalis API key, sent either way:


    ```bash

    curl -H "Authorization: Bearer ak_..."
    "https://api.originalis.ai/api/v1/deals"

    curl -H "X-API-Key: ak_..."           
    "https://api.originalis.ai/api/v1/deals"

    ```


    Keys are bound to a user in your org; identity and org scope are resolved

    **server-side** from the key — the API never accepts a client-supplied

    user or organization.


    ## Scope: whose data comes back


    Each response declares its scope explicitly:


    | `scope` | Meaning | Endpoints |

    | --- | --- | --- |

    | `org` / `org_shared` / `org_workspace` | Your whole firm's data (network
    scopes pool only across members who opted into sharing) | who-knows, warmth
    lookup, deals, portfolio, funds |

    | `key_user` | The graph of the specific user the key is bound to |
    contacts, reach candidates, going-stale signals |


    ## Shaping responses


    Detail reads accept a `view` query parameter, so pollers and dashboards

    aren't forced to carry full analysis bodies:


    - `GET /deals/{deal_id}?view=full` — adds `analysis`: every visible
      section of the deal record with its score and summary (default view
      stays the structured facts).
    - `GET /founders/analyses/{analysis_id}?view=full` — each metric adds
      `confidence`, `reasoning`, and `missing_info` alongside its score.
    - `GET /research/{research_id}?view=summary` — lifecycle + executive
      summary only; the default (`full`) carries the entire Markdown report
      and citations.

    Views only add or withhold optional fields — the schema of each response

    is identical across views, so typed clients need no variants.


    ## Pagination


    Three styles, stated per endpoint:


    - **Offset** (`/deals`, `/portfolio/companies`): responses carry `total`,
      `limit`, `offset`, `has_more`. Sweep with `offset += limit` until
      `has_more` is `false`.
    - **Cursor** (`/network/contacts`): pass each response's `next_cursor`
      back as `?cursor=` until it is `null`. Stable under concurrent writes.
    - **Whole-book** (`/funds/positions`, `/funds/cashflows`,
      `/funds/marks`): LP books are small; one call returns everything.

    ## Errors


    Errors are JSON with a human-readable `detail`:


    ```json

    { "detail": "Invalid or revoked API key." }

    ```


    (Validation `422`s carry the standard structured `detail` list naming

    the offending parameter.)


    Responses carry an `X-Request-Id` header (the rare unhandled 500 is

    the one exception). Quote it when you contact support and we can trace

    the exact request in our logs.


    | Code | Meaning |

    | --- | --- |

    | `401` | Missing, invalid, revoked, or expired key |

    | `403` | Key's user belongs to no organization |

    | `404` | Resource doesn't exist or isn't visible to the key's user |

    | `409` | Conflict: a duplicate analysis already in flight, a webhook URL
    already registered, or an idempotency key from another workspace |

    | `422` | Invalid parameters (the body names the parameter) |

    | `429` | Daily per-key limit reached — honor `Retry-After` (seconds until
    UTC midnight) |

    | `503` | A dependency is temporarily unavailable — retry with backoff. A
    failed read is **never** disguised as an empty result |


    ## Rate limits


    Each key has a daily request budget (default 5,000/day, resets at UTC

    midnight). Successful responses report where you stand:


    | Header | Meaning |

    | --- | --- |

    | `X-RateLimit-Limit` | The key's daily budget |

    | `X-RateLimit-Remaining` | Requests left today |

    | `X-RateLimit-Reset` | Seconds until the budget resets (UTC midnight) |


    `429` responses carry `Retry-After` (seconds). The headers are omitted

    on the rare request where the counter is unreachable — they are never

    guessed. Contact us if your integration needs a higher cap.


    ## Principles


    - **Your data, your scope.** Every response is scoped to your org. Warm
      paths pool only across teammates who opted into network sharing, and
      every path names its owner.
    - **Absence is honest.** Missing data comes back as `null` plus a typed
      `unavailable_reason` — never a defaulted or invented figure. Derived
      economics (TVPI, multiples) are null when their inputs are missing.
    - **Reads are pure; actions are explicit.** GET endpoints never mutate
      anything or trigger background work. The only endpoints that spend —
      `POST` actions like `/deals/analyze` — require a write-scoped key,
      draw down a separate daily budget, and always return `202` with a
      poll URL.
    - **Stable contract.** The `/api/v1` surface only changes additively:
      fields are added, never renamed, retyped, or removed.

    ## Actions (asynchronous)


    Actions run Originalis analysis pipelines on demand. They differ from

    reads in four deliberate ways:


    - **Write-scoped key required.** Mint a key with write access; read-only
      keys get `403`. Actions are the only endpoints that can spend.
    - **Separate budget.** Each key gets an actions budget (default 25/day,
      resets at UTC midnight) on top of the request limit — actions run
      real analysis pipelines with real cost. The budget is charged only
      when a run is actually dispatched: rejected, deduplicated, and
      conflicting requests cost nothing. Over-budget returns `429` with
      `Retry-After` plus `X-Actions-Limit` / `X-Actions-Remaining`.
    - **Always asynchronous.** Every action returns `202` immediately with
      a `status_url`; analysis takes minutes. Poll with backoff:

    ```bash

    DEAL=$(curl -s -X POST -H "X-API-Key: $KEY" -H "Content-Type:
    application/json" \
      -d '{"website_url": "https://acmerobotics.com"}' \
      "https://api.originalis.ai/api/v1/deals/analyze")
    STATUS_URL="https://api.originalis.ai$(echo "$DEAL" | jq -r '.status_url')"

    while :; do
      S=$(curl -s -H "X-API-Key: $KEY" "$STATUS_URL" | jq -r '.status')
      [ "$S" = "succeeded" ] || [ "$S" = "failed" ] || { sleep 30; continue; }
      break
    done

    curl -s -H "X-API-Key: $KEY" "https://api.originalis.ai$(echo "$DEAL" | jq
    -r '.result_url')"

    ```


    - **One status vocabulary.** Every action reports
      `queued → running → succeeded | failed`, and a `succeeded` action's
      `result_url` points back into the read API — results are ordinary
      resources, never a second schema.
    - **Live progress while polling.** A running action's status read
      carries a `progress` object — pipeline stages for deal analysis, the
      current stage for founder analysis, stage + percent for research — so
      a poller can show real movement, not a spinner.
    - **Or stream it (SSE).** Append `/events` to an analysis resource for a
      Server-Sent Events stream of the same payloads:
      `GET /api/v1/deals/{deal_id}/analysis/events`,
      `GET /api/v1/founders/analyses/{analysis_id}/events`,
      `GET /api/v1/research/{research_id}/events`. Named events: `progress`
      (emitted on change), `done` (terminal, carries `result_url`, then the
      server closes), `error` (stream-level problem — reconnect or fall
      back to polling); keep-alive comments every 25s. Authenticate with
      the same key header (`curl -N -H "X-API-Key: $KEY" ...`). Streams are
      not resumable — on reconnect the first `progress` event re-hydrates
      you. For backends that can't hold a connection, use webhooks (below);
      polling always works.

    Duplicate protection: a concurrent submission for the same target (the

    same company domain in your org) returns `409` rather than silently

    starting a second run.


    ## Webhooks


    The push door: register an HTTPS endpoint and Originalis POSTs a signed

    event when an action reaches a terminal state — no polling, no open

    connection.


    | Event | Fires when |

    | --- | --- |

    | `deal.analysis.completed` / `.failed` | A deal analysis finishes (or
    terminally fails) |

    | `founder.analysis.completed` / `.failed` | A founder assessment finishes |

    | `research.completed` / `.failed` | A research run finishes |


    Payloads are deliberately **thin** — fetch the resource for truth:


    ```json

    {
      "event": "deal.analysis.completed",
      "id": "9c0d1e2f-3a4b-4c5d-8e6f-7a8b9c0d1e2f",
      "created_at": "2026-09-07T15:04:05Z",
      "data": {
        "entity_id": "8a9b0c1d-2e3f-4a5b-9c6d-7e8f9a0b1c2d",
        "result_url": "/api/v1/deals/8a9b0c1d-2e3f-4a5b-9c6d-7e8f9a0b1c2d"
      }
    }

    ```


    **Verification** follows the [Standard
    Webhooks](https://www.standardwebhooks.com)

    scheme, so off-the-shelf verifier libraries work. Each delivery carries

    `webhook-id`, `webhook-timestamp`, and `webhook-signature`

    (`v1,base64(HMAC-SHA256(secret, "{id}.{timestamp}.{body}"))`):


    ```python

    import base64, hashlib, hmac


    def verify(secret: str, headers: dict, body: bytes) -> bool:
        key = base64.b64decode(secret.removeprefix("whsec_"))
        message = (
            f"{headers['webhook-id']}.{headers['webhook-timestamp']}."
            + body.decode()
        )
        expected = "v1," + base64.b64encode(
            hmac.new(key, message.encode(), hashlib.sha256).digest()
        ).decode()
        return hmac.compare_digest(expected, headers["webhook-signature"])
    ```


    **Delivery semantics**: at-least-once. Failed deliveries retry with

    exponential backoff — up to 11 attempts over roughly 30 minutes. A 4xx

    from your receiver stops retries immediately (except 408 and 429, which

    retry like a 5xx). Deduplicate on

    `webhook-id` — it is stable across retries. Answer with a 2xx within

    10 seconds; do slow work after acknowledging. Endpoints must be HTTPS

    on a public address; the secret is shown once at registration. Inspect

    recent deliveries at `GET /api/v1/webhooks/{webhook_id}/deliveries`.


    Known gap (documented, not silent): a run failed by the background

    stale-timeout sweep may not produce a webhook — the poll endpoints

    remain the source of truth.


    ## Recipes


    **Sync the pipeline into a warehouse** — page until `has_more` is false:


    ```bash

    OFFSET=0

    while :; do
      PAGE=$(curl -s -H "X-API-Key: $KEY" \
        "https://api.originalis.ai/api/v1/deals?limit=50&offset=$OFFSET")
      echo "$PAGE" | jq -c '.deals[]' >> deals.ndjson
      [ "$(echo "$PAGE" | jq '.has_more')" = "true" ] || break
      OFFSET=$((OFFSET + 50))
    done

    ```


    **Enrich a CRM with warmth** — batch up to 100 identifiers per call:


    ```bash

    curl -s -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
      -d '{"contacts": ["jane@acme.com", "sam@beta.io"]}' \
      "https://api.originalis.ai/api/v1/network/warmth/lookup" | jq '.results'
    ```


    **Quarterly LP reconciliation** — positions plus the raw cashflow ledger:


    ```bash

    curl -s -H "X-API-Key: $KEY"
    "https://api.originalis.ai/api/v1/funds/positions" \
      | jq '.totals'
    curl -s -H "X-API-Key: $KEY"
    "https://api.originalis.ai/api/v1/funds/cashflows" \
      | jq '.cashflows[] | select(.cashflow_date >= "2026-07-01")'
    ```


    **Relationship-drift alerting** — pipe going-stale signals anywhere:


    ```bash

    curl -s -H "X-API-Key: $KEY" \
      "https://api.originalis.ai/api/v1/network/signals/going-stale?limit=10" \
      | jq -r '.signals[] | "\(.name): \(.days_since_last_touch)d since last touch"'
    ```


    ## Connect an AI agent (MCP)


    Originalis is also a [Model Context
    Protocol](https://modelcontextprotocol.io)

    server — the same API key, a different door:


    ```text

    https://api.originalis.ai/mcp

    ```


    - **Claude Code**:
      `claude mcp add --transport http originalis https://api.originalis.ai/mcp --header "Authorization: Bearer ak_..."`
    - **Claude.ai / Claude Desktop**: add a custom connector with that URL —
      signing in with your Originalis account (OAuth) works there too. Or
      start from the in-app install page at
      [Integrations → Claude](https://app.originalis.ai/app/integrations/claude-ai).

    The MCP surface is deliberately a **single conversational tool** (`ori`)

    that reaches the full Originalis workspace — deal lookups, memos,

    research, network questions — with real thread continuity, rather than a

    zoo of per-endpoint tools.


    **Which door to use:** this REST API for deterministic, typed

    integrations (CRMs, warehouses, scheduled jobs — anything written in

    code against a stable contract, including the async actions); MCP for

    AI assistants that converse — the agent reaches the full workspace

    conversationally, governed by your account's permissions.


    ## OpenAPI & SDKs


    The machine-readable contract lives at

    [`https://api.originalis.ai/api/v1/openapi.json`](https://api.originalis.ai/api/v1/openapi.json)

    (OpenAPI 3.1, unauthenticated). Point any generator at it — Stainless,

    Speakeasy, Fern, `openapi-generator` — to produce a typed client in your

    language.


    ## Changelog


    - **1.10.0** (2026-09-08) — document inputs: `POST /deals/analyze` accepts
      `document_url` (DocSend — with password + server-side email
      verification — Notion, Canva, Dropbox, Google Drive, Figma, Gamma);
      new `POST /deals/analyze/upload` (multipart PDF/PPT/DOC, 50 MB);
      data-room endpoints `POST`/`GET /deals/{deal_id}/documents`.
    - **1.9.0** (2026-09-08) — response shaping: `?view=full` on deal and
      founder detail reads (per-section analysis; per-metric confidence +
      reasoning), `?view=summary` on research reads (lifecycle without the
      report body).
    - **1.8.1** (2026-09-08) — production hardening: keys are strictly
      org-scoped on every read (cross-org rows are a plain 404); the
      actions budget is charged only when a run dispatches; per-key caps on
      concurrent event streams; webhook retries widened to ~30 minutes.
    - **1.8.0** (2026-09-07) — webhooks: signed terminal-event delivery
      (Standard Webhooks conventions), endpoint management + delivery
      ledger under `/webhooks`.
    - **1.7.0** (2026-09-07) — SSE streams for every action
      (`.../events`): `progress` on change, `done` with `result_url`,
      25s keep-alives.
    - **1.6.0** (2026-09-07) — live `progress` on all three action status
      reads (deal pipeline stages, founder stage, research stage + percent).
    - **1.5.0** (2026-09-07) — research actions: `POST /research`
      (idempotent by required key, per-user live-run gate) +
      `GET /research/{research_id}` with the cited Markdown report.
    - **1.4.0** (2026-09-07) — founder analysis actions:
      `POST /founders/analyze` (org-deduped, `existing: true` on a cache
      hit) + `GET /founders/analyses/{analysis_id}`.
    - **1.3.0** (2026-09-07) — first actions: `POST /deals/analyze` +
      `GET /deals/{deal_id}/analysis`. Write-scoped keys, per-key daily
      actions budget, shared async status vocabulary.
    - **1.2.1** (2026-09-02) — stable `operationId` on every operation (SDK
      and agent friendly), curated examples on every response, documented
      error bodies, and `X-Request-Id` / `X-RateLimit-*` headers.
    - **1.2.0** (2026-09-02) — added metric time-series
      (`/portfolio/companies/{company_id}/metrics`) and LP mark history
      (`/funds/marks`).
    - **1.1.0** (2026-09-02) — added Deals (`/deals`, `/deals/{deal_id}`),
      Portfolio (`/portfolio/companies`), and Funds (`/funds/positions`,
      `/funds/cashflows`).
    - **1.0.0** (2026-09-01) — initial release: Network Intelligence
      (who-knows, warmth lookup, contacts export, reach candidates,
      going-stale signals).
  version: 1.10.0
servers:
  - url: https://api.originalis.ai
security:
  - ApiKeyBearer: []
  - ApiKeyHeader: []
tags:
  - name: public-network-v1
    x-displayName: Network Intelligence
    description: >-
      Your firm's relationship graph, evidenced by your team's own emails and
      calendars. Warm paths pool across org members who opted into network
      sharing, and every path names the teammate who owns the relationship.
  - name: public-deals-v1
    x-displayName: Deals
    description: >-
      The org's deal workspace — the same cohort the in-app pipeline shows.
      Listings are offset-paginated for full sweeps; the detail read returns the
      structured record for one deal.
  - name: public-founders-v1
    x-displayName: Founders
    description: >-
      Programmatic founder assessment — the research-agent pipeline behind the
      in-app founder surface. Deduped per org: an already-assessed founder
      returns the existing analysis, never a second spend.
  - name: public-research-v1
    x-displayName: Research
    description: >-
      Programmatic deep research: submit a question, get a citation-backed
      Markdown report. Idempotent by key; runs take minutes and execute
      asynchronously.
  - name: public-portfolio-v1
    x-displayName: Portfolio
    description: >-
      The org's portfolio book. Economics come from the fund-investment ledger
      and metrics from the canonical latest-actuals resolver — the same sources
      the in-app hub reads.
  - name: public-funds-v1
    x-displayName: Funds (LP Book)
    description: >-
      LP fund commitments: positions with null-honest derived economics
      (TVPI/DPI/unfunded), coverage-counted book totals, and the dated cashflow
      ledger for reconciliation.
  - name: public-webhooks-v1
    x-displayName: Webhooks
    description: >-
      Signed event delivery when actions reach terminal states — Standard
      Webhooks conventions, so off-the-shelf verifiers work. Secrets are shown
      once; a delivery ledger backs debugging.
paths:
  /api/v1/founders/analyze:
    post:
      tags:
        - public-founders-v1
      summary: Analyze a founder
      description: |-
        Run an Originalis founder assessment.

        Deduped per org: if your org already assessed this founder (or a run
        is in flight), you get the existing analysis back with
        `existing: true` — no new run is started or billed. Otherwise the
        research-agent pipeline runs asynchronously (typically minutes);
        poll `status_url`.

        Requires a write-scoped API key and draws down the daily actions
        budget.
      operationId: analyzeFounder
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FounderAnalyzeRequest'
            example:
              name: Ada Founder
              linkedin_url: https://linkedin.com/in/adafounder-example
              company: Acme Robotics
        required: true
      responses:
        '202':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FounderAnalyzeResponse'
              example:
                analysis_id: d4e5f6a7-8b9c-4d0e-8f1a-2b3c4d5e6f7a
                founder_name: Ada Founder
                status: running
                existing: false
                status_url: /api/v1/founders/analyses/d4e5f6a7-8b9c-4d0e-8f1a-2b3c4d5e6f7a
                result_url: /api/v1/founders/analyses/d4e5f6a7-8b9c-4d0e-8f1a-2b3c4d5e6f7a
                as_of: '2026-09-02T14:00:00Z'
          headers:
            X-Request-Id:
              description: Correlation id for this request — quote it to support.
              schema:
                type: string
            X-RateLimit-Limit:
              description: The key's daily request budget.
              schema:
                type: integer
            X-RateLimit-Remaining:
              description: Requests left today. Omitted when the counter is unavailable.
              schema:
                type: integer
            X-RateLimit-Reset:
              description: Seconds until the budget resets at UTC midnight.
              schema:
                type: integer
        '401':
          description: Missing, invalid, revoked, or expired API key.
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
                required:
                  - detail
              example:
                detail: Invalid or revoked API key.
        '403':
          description: The key's user belongs to no organization.
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
                required:
                  - detail
              example:
                detail: >-
                  This API key's user does not belong to an organization. Ask
                  your firm admin to add the user to your Originalis org.
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          description: >-
            Daily per-key request budget exhausted. Honor `Retry-After` (seconds
            until UTC midnight).
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
                required:
                  - detail
              example:
                detail: >-
                  Daily request limit reached (5,000 requests per key). The
                  limit resets at UTC midnight.
        '503':
          description: >-
            A dependency is temporarily unavailable — retry with backoff. A
            failed read is never disguised as an empty result.
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
                required:
                  - detail
              example:
                detail: >-
                  API key verification is temporarily unavailable. Retry
                  shortly.
components:
  schemas:
    FounderAnalyzeRequest:
      properties:
        name:
          anyOf:
            - type: string
              maxLength: 300
            - type: 'null'
          title: Name
          description: Founder's full name.
        linkedin_url:
          anyOf:
            - type: string
              maxLength: 1024
            - type: 'null'
          title: Linkedin Url
          description: LinkedIn profile URL.
        github_url:
          anyOf:
            - type: string
              maxLength: 1024
            - type: 'null'
          title: Github Url
          description: GitHub profile URL.
        company:
          anyOf:
            - type: string
              maxLength: 300
            - type: 'null'
          title: Company
          description: Current company — a discovery hint, not required.
        context:
          anyOf:
            - type: string
              maxLength: 20000
            - type: 'null'
          title: Context
          description: Free-form context for the assessment (notes, emails).
      type: object
      title: FounderAnalyzeRequest
      description: |-
        Submit a founder for an Originalis assessment.

        Provide at least one identity signal: a name, a LinkedIn URL, or a
        GitHub URL. A LinkedIn URL is the strongest key — name-only
        submissions dedupe on the name alone.
    FounderAnalyzeResponse:
      properties:
        analysis_id:
          type: string
          title: Analysis Id
        founder_name:
          type: string
          title: Founder Name
        status:
          type: string
          enum:
            - queued
            - running
            - succeeded
            - failed
          title: Status
        existing:
          type: boolean
          title: Existing
          description: >-
            True when your org already had this founder assessed (or a run in
            flight) — you were handed the existing analysis and NO new run was
            started or billed.
        status_url:
          type: string
          title: Status Url
          description: Poll GET here until status is 'succeeded' or 'failed'.
        result_url:
          type: string
          title: Result Url
        as_of:
          type: string
          format: date-time
          title: As Of
      type: object
      required:
        - analysis_id
        - founder_name
        - status
        - existing
        - status_url
        - result_url
        - as_of
      title: FounderAnalyzeResponse
      description: Accepted founder-analysis submission (HTTP 202).
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
  securitySchemes:
    ApiKeyBearer:
      type: http
      scheme: bearer
      description: 'An Originalis API key: `Authorization: Bearer ak_...`'
    ApiKeyHeader:
      type: apiKey
      in: header
      name: X-API-Key

````