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

# List opportunities

> 
Returns a paginated list of opportunities visible to the tenant ring.

Filter parameters (all optional):
- name: Case-insensitive substring match on the opportunity's own name
- search: Fuzzy search across name and associated person/company names
- opportunity_type_uuid: Filter by opportunity type UUID (use GET /v1/opportunities
  to inspect `type.uuid` on existing records)
- opportunity_stage_uuid: Filter by a single stage UUID
- opportunity_stage_uuids: Comma-separated stage UUIDs (IN filter)
- owner_user_uuid: Comma-separated user UUID(s); filters by owner
- include_no_owner: Also include opportunities with no owner assigned
- intro_person_uuid: Filter by the intro person's UUID
- related_company_uuid / related_person_uuid: parent opportunities that have a
  sub-opportunity associated with this entity
- parent_uuid: Return only sub-opportunities of this parent UUID
- hierarchy_type: 'PARENT' or 'CHILD' (ignored if parent_uuid is set)
- company_uuid / person_uuid: Comma-separated UUID(s); union of opportunities
  associated with any of them
- value_from / value_to, probability_from / probability_to: inclusive range filters
- updated_after / updated_before: ISO 8601 date/datetime range on updated_at
- source_date_from / source_date_to: ISO 8601 dates, required together
- last_activity_date_from / last_activity_date_to: ISO 8601 datetimes, required
  together

Sort parameters:
- sort_by: name | created_at | updated_at | value | weighted_value | probability |
  source_date | intro_date | last_activity_date | details | next_step | stage |
  owner | intro_person | days_in_stage | notes_and_files_count
- order: asc | desc (default: asc)

Pagination:
- page: Page number (default: 1)
- per_page: Results per page (default: 50)

The response also includes `total_value`/`total_weighted_value`: sums of
`value`/`weighted_value` across the full filtered set, not just the page.



## OpenAPI

````yaml GET /v1/opportunities
openapi: 3.1.0
info:
  description: >

    ## Rings MCP server


    The Rings MCP server exposes tenant data to AI tools that support the

    [Model Context Protocol](https://modelcontextprotocol.io) (e.g. Claude,

    ChatGPT, Cursor). AI tools authenticate with your Rings account via OAuth
    2.0

    and can read and update data within what the authenticated user can already
    see

    and do in Rings. For server-side integrations, an API key may be used on MCP

    requests with the same tenant and rules as the REST API (see
    **Authentication**

    below).


    * **Server URL:** `https://production-api.joinrings.com/mcp`

    * **Auth:** OAuth 2.0. Actions are performed on behalf of the authenticated
    user;
      access is scoped to the same data and permissions as in the Rings app.
    * **Transport:** Streamable HTTP, **stateless** (no server-side MCP
    sessions).

    * **ChatGPT app:** [Rings
    AI](https://chatgpt.com/apps/rings-ai/asdk_app_6a32575772f481918f88503de126c411)


    ### Tools and this document


    MCP **tools** are generated from the **`/v1` operations** defined in this
    OpenAPI

    document. Each tool maps to an HTTP method and path; parameters and bodies
    match

    the schemas in the tagged sections below. For exact tool names and JSON
    schemas

    at runtime, use the MCP **`list_tools`** request in your client.


    ### What you can do with MCP today


    | **Area** | **Description** |

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

    | **Person** | People, PathPower, incremental lists, recommended paths |

    | **Company** | Orgs, affiliations, PathPower, incremental sync, recommended
    paths |

    | **Opportunity** | Deals, custom field mapping and values |

    | **Activity** | Email and meeting activity for persons and companies |

    | **Recommended paths** | Ranked contacts and multi-hop path context to a
    target |

    | **PathPower** | Relationship strength scores for persons and companies |

    | **Note** | Notes, rich content, entity associations |

    | **Task** | Tasks, assignees, due dates, reminders, associations |

    | **Users** | Tenant users (e.g. to set per-user context) |

    | **Meetings** | Calendar meetings, date and participant filters |

    | **AI summary** | Cached AI summaries for persons and companies |

    | **Entity List** | Named collections of companies or persons and their
    membership |

    | **Relationships** | Ring-wide and per-user relationships ranked by
    RQ/PathPower |


    ### Rate limiting


    MCP calls the same REST API underneath. **Per-second and monthly** limits
    apply

    (see **Rate Limiting** below). Responses may include **`429 Too Many
    Requests`**

    and the usual rate-limit headers.


    ### Use-case examples


    * **Meeting prep:** From chat, load a person, recent activity, and upcoming
    meetings.

    * **Capture follow-ups:** Tasks and notes via natural language (tenant
    rules).

    * **Relationship mapping:** Ask for PathPower or recommended paths before an
    intro.

    * **Create an opportunity:** List opportunity types, pick a type and one of
    its
      stages, then create the deal linked to a company or person.

    For a fuller walkthrough — meeting prep briefings, network navigation and

    analysis, pipeline management, workflow automation (inbound email → deal,

    call debriefs, handoffs), and searching firm notes/account history — see

    [Examples of Rings workflows users can do in Claude and
    ChatGPT](https://rings-ai-knowledge-base.help.usepylon.com/articles/2808798956-examples-of-rings-workflows-users-can-do-in-claude-and-chatgpt)

    in the knowledge base.


    ---


    ## Authentication


    All API requests require authentication using an API key provided in the

    `x-api-key` header.


    ### Getting an API Key


    API keys can be created through your account settings. Each API key is

    associated with a specific tenant and provides access to that tenant's data.


    ### Using Your API Key


    Include your API key in the `x-api-key` header for all requests:


    ```

    x-api-key: pk_your_api_key_here

    ```


    ### API Key Format


    API keys must start with the prefix `pk_` followed by a secure random
    string.

    Invalid or inactive API keys will return a `401 Unauthorized` response.


    ### Security


    - Keep your API keys secure and never commit them to version control

    - Rotate your API keys regularly

    - Revoke unused or compromised keys immediately

    - Each API key is scoped to a specific tenant and can only access that
      tenant's data

    ## Per-User Context


    API keys support two scopes that control how user context is resolved:


    ### Tenant-scoped keys (default)


    Include an optional `x-rings-user-id` header with the UUID of a user
    belonging

    to the API key's tenant:


    ```

    x-rings-user-id: <user-uuid>

    ```


    Use `GET /v1/users` to discover available user UUIDs. If the header is
    omitted,

    endpoints return tenant-wide data. If the user UUID is invalid or belongs to
    a

    different tenant, the API returns `403 Forbidden`.


    ### User-scoped keys


    User-scoped keys are permanently bound to a single user. The user context is

    automatically populated from the bound user on every request — no

    `x-rings-user-id` header is required.


    If `x-rings-user-id` is provided, it **must** match the bound user UUID;

    otherwise the API returns `403 Forbidden`. The API also returns `403
    Forbidden`

    if the bound user is missing or no longer active in the tenant.


    ## Rate Limiting


    The API enforces tiered rate limits to ensure fair usage and system
    stability.

    Limits vary by plan:


    | Tier | Per-Second | Monthly |

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

    | Standard | 5 req/s | 10,000 req/month |

    | Professional | 20 req/s | 100,000 req/month |

    | Enterprise | 50 req/s | 500,000 req/month |

    | Custom | Configured per tenant | Configured per tenant |


    Both per-second and monthly limits are enforced simultaneously. Limits are

    configured at the tenant level. Contact support to request a custom tier
    with

    specific per-second and monthly limits.


    ### Per-Second Limit


    Enforced per API key on a per-second basis to prevent burst traffic.


    ### Monthly Limit


    Tracked per tenant on a discrete calendar month basis (e.g., January 1-31,

    February 1-28/29), not a rolling 30-day window.


    ### Rate Limit Headers


    All API responses include rate limit information in the following headers:


    **Per-Second Headers:**

    - `X-RateLimit-Limit`: Maximum requests allowed per second for your tier

    - `X-RateLimit-Remaining`: Requests remaining in the current second

    - `X-RateLimit-Reset`: Unix timestamp (seconds) when the per-second limit
      resets (start of the next second)

    **Monthly Headers:**

    - `X-RateLimit-Limit-Monthly`: Maximum requests allowed per month for your
    tier

    - `X-RateLimit-Remaining-Monthly`: Requests remaining in the current month

    - `X-RateLimit-Reset-Monthly`: Unix timestamp (seconds) when the monthly
    limit
      resets (start of the next calendar month)

    ### Rate Limit Exceeded


    When you exceed either limit, the API returns a `429 Too Many Requests`

    response with the following information:


    - **Status Code**: `429`

    - **Response Body**: Error message indicating which limit has been exceeded

    - **Headers**: Rate limit headers with the exceeded limit's remaining count
      set to `0`
    - **Retry-After**: Header indicating seconds to wait before retrying (for
      per-second limits)

    ### Rate Limit Reset


    - **Per-Second Limit**: Resets at the start of each second

    - **Monthly Limit**: Resets automatically at the start of each calendar
    month
      (00:00:00 UTC on the 1st of each month)

    ### Best Practices


    - Monitor both `X-RateLimit-Remaining` headers to track your usage

    - Implement exponential backoff if you receive a 429 response

    - Respect the `Retry-After` header when provided

    - Plan your API usage to stay within both limits

    - Consider caching responses when appropriate to reduce API calls

    - Use request batching when possible to minimize per-second usage


    ## Request Correlation


    Every API response includes an `X-Request-Id` header containing a UUID that

    uniquely identifies the request. This header is useful for correlating
    client

    requests with server-side logs when troubleshooting failures.


    If your client or gateway already generates a request ID, you may forward it
    by

    including an `X-Request-Id` header on the incoming request — the same value

    will be echoed back in the response. If no header is provided, the API
    generates

    a fresh UUID automatically.
  title: Rings AI API
  version: v1.2.2
servers:
  - description: API server
    url: https://production-api.joinrings.com
security:
  - ApiKeyAuth: []
tags:
  - description: >-
      Operations related to persons.


      ## Strongest relationships


      Person detail and list responses include a `strongest_relationships` array
      — up to two tenant internal users with the strongest relationship to the
      subject, ranked by `priority_management.rq_pretty` (desc). Values are
      precomputed every ~3 hours by a background job so the field is cheap to
      surface on list endpoints. Tenants with no `Signal` rows are skipped
      during precomputation and will see `strongest_relationships = null`.


      `last_engaged_at` on each row is sourced from the tenant-wide activity
      stats table and may lag while the activity-stats pipeline is in
      remediation.


      ## Filtering by modification time


      List endpoints accept `modified_since` (ISO 8601); it filters on
      `rings_updated_at`, the system-wide updated timestamp on each record. Use
      this for incremental sync workflows rather than polling the full page.


      ## Last contact timestamp


      `last_contact_at` is tenant-wide and aliases `last_activity_date`; both
      fields are populated from the same `ActivityDateByEntity` source.


      ## Next meeting


      `next_meeting_at`, `next_meeting_title`, and `next_meeting_with_user_uuid`
      reflect the earliest future calendar event (Activity.kind=EVENT,
      non-cancelled, start_date >= now) involving this person, tenant-wide.
      `my_next_meeting_at` and `my_next_meeting_title` narrow to events where
      the calling user (identified via `x-rings-user-id`) is a participant; they
      are `null` when no user context is provided. Backed by materialized tables
      refreshed by event listeners plus an hourly Celery sweep.


      ## Bulk import


      For importing many people at once:


      - `POST /v1/persons/lookup/batch` resolves up to 100 match criteria
      (email/linkedin_url/domain) in one call — use this first to find existing
      records.

      - `POST /v1/persons/batch` match-or-creates up to 50 persons in one call:
      each entry that matches an existing tenant-visible person is returned
      as-is (status `MATCHED`); unmatched entries are created (status
      `CREATED`). Items are processed independently, so one failing row (status
      `ERROR`) doesn't sink the batch. Results are returned in input order.

      - Typical import flow: `POST /v1/persons/lookup/batch` → `POST
      /v1/persons/batch` for the unmatched remainder → `POST /v1/notes/batch` to
      attach notes to the results (see the **Note** tag).


      ## Merging duplicate persons


      `POST /v1/persons/{uuid}/merge` merges a superseded person into the
      canonical person named in the path, reassigning notes, associations,
      activity, and other references before removing the superseded record.
      Merging is always scoped to the caller's own tenant — there is no option
      for a GLOBAL-scope or cross-tenant merge, and no way to force
      global-record promotion or other admin-only controls. Set `preview: true`
      for a read-only dry run: nothing persists, and the response's `preview`
      field describes the canonical/superseded/merged entities as they would
      look post-merge. Returns `404` if either UUID doesn't exist, `409` if the
      two UUIDs are already merged (or identical), and `400` for other merge
      validation errors (e.g. using a shared global record as the canonical
      side).
    name: Person
  - description: >-
      Operations related to companies.


      ## Strongest relationships


      Company detail and list responses include a `strongest_relationships`
      array — up to two tenant internal users with the strongest relationship
      into the company, computed by taking the best
      `priority_management.rq_pretty` an internal user has against any person
      currently affiliated with the company. Values are precomputed every ~3
      hours on the same cadence as the person endpoints, so list pages issue a
      single batched lookup rather than per-item work.


      `last_engaged_at` on each row is sourced from the tenant-wide activity
      stats table (keyed on the company entity) and may lag while the
      activity-stats pipeline is in remediation.


      ## Filtering by modification time


      List endpoints accept `modified_since` (ISO 8601); it filters on
      `rings_updated_at`, the system-wide updated timestamp on each record.


      ## Filtering the company list


      `GET /companies` accepts the same filter set as the web app's company
      explorer (see each query parameter for exact semantics). Filters compose
      with AND:


      - **Identity / text** — `name`, `domain`, `linkedin_url`, `facebook_url`,
      `twitter_url`, `description` (case-insensitive substring).

      - **Location** — `city` (substring); `country` and `state` (resolved via
      pycountry, matched on the canonical name).

      - **Status (comma-separated, OR within a field)** — `operating_status`,
      `acquisition_status`, `ipo_status`.

      - **Tags / investors** — `rings_industry_tags` with
      `rings_industry_tags_operator` (`AND`/`OR`); `investor_types`,
      `last_investment_types`, `npi_types`.

      - **Numeric ranges (inclusive)** — `founded_on_from/to`, `score_from/to`,
      `employee_count_from/to`, `overall_operating_score_from/to`,
      `overall_investor_score_from/to`.

      - **Date ranges (ISO 8601, both bounds required)** —
      `last_investment_date_from/to`, `npi_date_from/to`.

      - **By identity** — `uuids` (comma-separated).


      ## Last contact timestamp


      `last_contact_at` is tenant-wide and aliases `last_activity_date`; both
      fields read from the same `ActivityDateByEntity` source used by the
      list/detail endpoints.


      ## Next meeting


      `next_meeting_at`, `next_meeting_title`, and `next_meeting_with_user_uuid`
      reflect the earliest future calendar event involving this company,
      tenant-wide. `my_next_meeting_at` and `my_next_meeting_title` narrow to
      events where the calling user (identified via `x-rings-user-id`) is a
      participant; they are `null` when no user context is provided. Same
      materialized source as the person endpoints.
    name: Company
  - description: >-
      Operations related to sales opportunities.


      ## Filtering the opportunity list


      `GET /v1/opportunities` filters compose with AND (unless noted). See each
      query parameter for exact semantics.


      - **Identity / text** — `name` (substring match on the opportunity's own
      name); `search` (fuzzy match across name and associated person/company
      names — broader than `name`).

      - **Type / stage** — `opportunity_type_uuid`; `opportunity_stage_uuid`
      (single) or `opportunity_stage_uuids` (comma-separated IN filter).

      - **Ownership** — `owner_user_uuid` (comma-separated user UUIDs, OR'd
      together) and `include_no_owner` (OR'd with `owner_user_uuid` when both
      are set); `intro_person_uuid`.

      - **Hierarchy** — `parent_uuid` (sub-opportunities of this parent) or
      `hierarchy_type` (`PARENT`/`CHILD`, ignored when `parent_uuid` is set —
      with neither set, both parents and children are returned);
      `related_company_uuid` / `related_person_uuid` (parent opportunities with
      a *sub*-opportunity associated with this entity — distinct from
      `company_uuid`/`person_uuid` below).

      - **Associated entities** — `company_uuid` / `person_uuid`
      (comma-separated; union of opportunities directly associated with any of
      them).

      - **Numeric ranges (inclusive)** — `value_from`/`value_to`,
      `probability_from`/`probability_to`.

      - **Date ranges** — `updated_after`/`updated_before` (ISO 8601
      date/datetime, independent bounds); `source_date_from`/`source_date_to`
      and `last_activity_date_from`/`last_activity_date_to` (ISO 8601, **both
      bounds required together** — a single-sided value is a no-op).


      ### Sorting


      `sort_by` accepts `name`, `created_at`, `updated_at`, `value`,
      `weighted_value`, `probability`, `source_date`, `intro_date`,
      `last_activity_date`, `details`, `next_step`, `stage` (pipeline stage
      order), `owner` (by name), `intro_person` (by name), `days_in_stage`, and
      `notes_and_files_count`, plus `order` (`asc`/`desc`). Sorting by `owner`,
      `intro_person`, `days_in_stage`, or `notes_and_files_count` is more
      expensive than the other keys since those columns only exist after
      enriching the full filtered set (not just the returned page).


      ### Totals


      The list response includes `total_value` and `total_weighted_value` — sums
      of `value`/`weighted_value` across the *entire filtered set*, not just the
      current page.


      ## Custom field mapping


      `GET /v1/opportunities/{uuid}` and each list response include a
      `custom_field_mapping` object containing:


      - `fields[]` — all tenant custom field definitions, each with `uuid`,
      `key`, `name`, `type`, and optional `choices`

      - `standard_key_to_uuid` — explicit `{key: uuid}` map for the 16 standard
      column keys that are resolved for this tenant (null when none are
      resolved)

      - `unresolved_keys` — standard column keys that have no matching custom
      field for this tenant (null when all are present)


      On `GET /v1/opportunities` (list), `custom_field_mapping` is carried once
      at the top level of the response rather than repeated on every item —
      items themselves do not carry the field.


      ### Custom field lookup


      Use `standard_key_to_uuid` to translate a web-app column name (e.g.
      `targetSize`) to the `uuid` used as the key in the opportunity's
      `custom_fields` JSONB. The full `fields[]` list provides additional
      metadata (display name, type, choices) for every custom field.


      ### Standard column keys


      The following 16 keys are standard columns in the Rings web app. Resolved
      keys appear in `standard_key_to_uuid`; any that are not configured appear
      in `unresolved_keys`:


      `targetSize`, `segment`, `priority`, `industry`, `postMoneyValuation`,
      `dealSize`, `fundCost`, `noteDiscount`, `fundFmvAsOf`,
      `preMoneyValuation`, `indicativePrice`, `source`, `dataRoomLink`,
      `result`, `resultDetails`, `nextStepDate`
    name: Opportunity
  - description: >
      Activity history — emails, meetings, and other interactions associated
      with a person or company.


      ## Response field names


      | Field | Description |

      |---|---|

      | `activity_id` | Internal activity identifier |

      | `object_id` | External source identifier |

      | `activity_type` | `"email"` or `"meeting"` |

      | `activity_timestamp` | ISO-8601 date/time of the activity |

      | `start_time` | Meeting start (ISO-8601, meetings only) |

      | `end_time` | Meeting end (ISO-8601, meetings only) |

      | `subject` | Email subject line (emails only) |

      | `from_email` | Sender email address (emails only) |

      | `body` | Email body text or meeting notes |

      | `participants` | All participants |

      | `cc_participants` | CC recipients (emails only) |
    name: Activity
  - description: >
      Recommended relationship paths — ranked contacts that connect you to a
      target person or company via multi-hop relationships.


      Results are ranked by PathPower score (highest first by default). Each
      contact includes a `strength` label and `connection_score` derived from
      PathPower. See the **PathPower** tag for score interpretation details.


      ## How paths are derived


      ```
        ┌─────────────────────────────────────────────────┐
        │           Recommended Paths Pipeline            │
        └─────────────────────────────────────────────────┘

        1. Query affiliations for the target entity
        2. Score each affiliated person with PathPower
        3. Enrich with priority_management signals
        4. Build paths from signals with rq_pretty > 0

        ┌──────────┐    signal (RQ>0)    ┌──────────────┐
        │ Colleague├───────────────────►  │ Target Person│
        │ (hop 0)  │    rq_pretty=2       │   (hop 1)    │
        └──────────┘                      └──────────────┘

        Each signal with rq_pretty > 0 produces one 2-hop path:
          paths[i] = [ colleague_hop, target_hop ]

        Example with 2 qualifying signals:

        ┌─────────┐
        │  Alice   │──► ┐
        │  RQ = 3  │    │    ┌──────────────┐
        └─────────┘    ├──► │ Target Person │
        ┌─────────┐    │    │  pp_score=0.7 │
        │   Bob    │──► ┘    └──────────────┘
        │  RQ = 2  │
        └─────────┘

        paths = [
          [ {Alice, score=3}, {Target, score=3} ],
          [ {Bob,   score=2}, {Target, score=3} ]
        ]
        path_count = 2
      ```


      ## Response structure


      Each `RecommendedContact` includes:


      - **Identity**: `person_uuid`, `name`, `job_title`, `email`, `logo_url`,
      `linkedin_url`, `facebook_url`, `twitter_url`

      - **PathPower**: `connection_score` (RQ-style integer 1-3), `strength`
      label, `path_count`

      - **Paths**: `paths[]` — array of hop arrays representing relationship
      paths to the target

      - **Company**: `company_name`, `primary_company` object with `uuid`,
      `name`, `logo_url`, and `is_primary_company_recommended`

      - **Role tags**: `tags[]` — deduplicated role labels (e.g. "founder",
      "ceo")

      - **Emails**: `emails[]` — all known email addresses with `address`,
      `is_primary`, `last_seen_at`

      - **Signal metadata**: `signal_metadata` — counts of `lists` and
      `associations` linked to this contact

      - **Priority management**: `priority_management[]` — per-user relationship
      quality signals


      ## paths[] and path_count


      `paths` is an array of arrays. Each inner array is a sequence of `PathHop`
      objects representing one relationship path from an organisation colleague
      to the target contact.


      Paths are derived from `priority_management` signals: each signal with
      `rq_pretty > 0` produces a 2-hop path `[colleague → target]`. `path_count
      = len(paths)`.


      ### No qualifying signals


      When no signals with `rq_pretty > 0` exist for a contact, the contact is
      still returned but with `paths=[]` and `path_count=0`. The contact card is
      still shown, just without an expandable paths section.


      ### PathHop fields


      | Field | Type | Description |

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

      | `person_uuid` | string | Person UUID for this hop |

      | `name` | string | Full name |

      | `job_title` | string | Current title (target hop only) |

      | `company_name` | string | Current company (target hop only) |

      | `logo_url` | string | Avatar/photo URL |

      | `connection_score` | int | RQ score (1-3) — from PathPower on target
      hop, from signal `rq_pretty` on colleague hop |

      | `associations` | string[] | Association count labels |

      | `ring_name` | string | Organisation display name (colleague hop only) |

      | `ring_key` | string | Stable tenant slug (colleague hop only) |

      | `linkedin_url` | string | LinkedIn profile URL |

      | `last_interaction_at` | string | ISO timestamp of the most recent
      activity between this hop and the next one in the path (colleague/"you"
      hop only — `null` on the target hop, which has no single-pair signal) |

      | `interaction_count` | int | Count of activities backing that same pair
      (colleague/"you" hop only). Use with `last_interaction_at` to tell a
      thin-but-live RQ 1 connection (recent date, count > 1) from a stale one
      (old date, count = 1) — `connection_score` alone can't make that
      distinction |


      ## connection_score semantics


      `connection_score` on the top-level `RecommendedContact` is an RQ-style
      integer (1-3) derived from the PathPower score:


      | connection_score | PathPower range | strength label |

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

      | 1 | 0.00 - 0.20 | weak |

      | 2 | 0.21 - 0.60 | moderate / strong |

      | 3 | 0.61 - 1.00 | very_strong |


      ## Priority management signals


      Each entry in `priority_management` represents one user's assessment of
      the relationship with the contact:


      | Field | Description |

      |---|---|

      | `user_name` | Name of the user who set the signal |

      | `user_uuid` | UUID of that user |

      | `rq_pretty` | Relationship Quality score (1-3) |

      | `priority_score` | Priority Score set by the user |

      | `rq_reason` | Reason for the RQ rating |

      | `priority_context` | Priority context tags |

      | `last_activity_date` | ISO timestamp of the most recent activity between
      this user and the contact |

      | `interaction_count` | Count of activities backing this signal. Both
      fields are scoped to this specific (user, contact) pair, not tenant-wide —
      use them to distinguish a thin-but-live RQ 1 from a single stale email,
      since `rq_pretty` alone can't |


      ## top_external_contacts (company endpoint only)


      `GET /v1/companies/{uuid}/recommended-paths` additionally returns a
      top-level `top_external_contacts` array: the company's top external
      contacts (`is_internal=false`) ranked by PathPower, capped at 5. This
      array is independent of pagination — it always reflects the strongest
      external contacts across the whole result set, not just the current page.
      The person endpoint omits this field (`null`).


      Each entry contains:


      | Field | Description |

      |---|---|

      | `person_uuid` | Person UUID of the external contact |

      | `name` | Contact name |

      | `job_title` | Contact title |

      | `tags` | Deduplicated company roles (e.g. employee, investor, advisor,
      board_member) — same values as `items[].tags` |

      | `strength` | PathPower band label (weak … very_strong) |

      | `connection_score` | RQ-style integer (1-3) |

      | `internal_connectors` | Up to 2 internal users with the strongest
      relationship to this contact — same shape as `strongest_relationships`
      (`name`, `path_power_score`, `last_engaged_at`) |
    name: Recommended Paths
  - description: >-
      PathPower measures the strength of your organisation's relationship to a
      person or company.


      ```
        ┌─────────────────────────────────────────────────┐
        │              PathPower Overview                 │
        └─────────────────────────────────────────────────┘

        Person PathPower:

          User A ──RQ signal──►┐
          User B ──RQ signal──►├──► Person X ──► score 0.0-1.0
          User C ──RQ signal──►┘

          Score derived from Relationship Quality (RQ) signals
          set by users in the organisation.

        Company PathPower:

          Person A (score 0.8) ──►┐
          Person B (score 0.6) ──►│
          Person C (score 0.5) ──►├──► avg(top 5) ──► Company score
          Person D (score 0.4) ──►│
          Person E (score 0.3) ──►┘

          Average of top 5 person scores affiliated
          with the company.

        Score mapping:

          0.0 ──────────── 0.2 ──── 0.4 ──── 0.6 ──────── 1.0
          │     Weak       │ Moderate│ Strong │ Very Strong │
      ```


      ## Score format


      - **Raw score**: `0.0`–`1.0` (stored in `score`)

      - **Display score**: `0`–`100` (stored in `score_display`, equals `score *
      100`)

      - **Strength label**: band key string in `strength_label`: `weak`,
      `moderate`, `strong`, `very_strong` (lowercase, underscores—these are
      stable API values, not title-cased prose).


      ## Strength labels and thresholds


      | strength_label value | Meaning | Score range |

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

      | weak | Weak | 0.00 - 0.20 |

      | moderate | Moderate | 0.21 - 0.40 |

      | strong | Strong | 0.41 - 0.60 |

      | very_strong | Very strong | 0.61 - 1.00 |


      A `null` score means no PathPower data exists for that entity.


      ## How scores are computed


      **Person scores** are derived from Relationship Quality (RQ) signals — the
      strength ratings that users in your organisation have assigned to their
      relationships with that person.


      **Company scores** are the average of the top 5 person PathPower scores
      among people affiliated with that company.


      ## Refresh cadence


      Scores are recomputed automatically every 3 hours. They are not
      triggerable via the API. If a score appears stale, it will update on the
      next refresh cycle.


      ## Related endpoints


      - PathPower is also returned inline on `GET /v1/persons` and `GET
      /v1/companies` responses (in the `pathpower` field).

      - `GET /v1/*/recommended-paths` returns contacts ranked by PathPower
      score.
    name: PathPower
  - description: >-
      Operations for tenant notes — rich-text notes that can be linked to
      people, companies, opportunities, files, and tasks via associations.


      ## Lifecycle


      - `POST /v1/notes` creates a note. The HTML body is stored in S3 keyed by
      note UUID; a plain-text excerpt is persisted on the row for cheap
      list/search access.

      - `PUT /v1/notes/{uuid}` updates note fields. Only supplied fields are
      written; passing `content` re-uploads the S3 object and refreshes the
      excerpt.

      - `DELETE /v1/notes/{uuid}` soft-deletes a note. Only the owner or a
      tenant **ringmaster** may delete; other users receive `403 Forbidden`.

      - `POST /v1/notes/batch` creates up to 50 notes in one call, each with its
      own inline `associations` and optional `idempotency_key` (re-submitting
      the same key returns the existing note, status `SKIPPED`, instead of
      duplicating it). One failing row (status `ERROR`) doesn't sink the rest of
      the batch — this is the note half of the bulk import flow described under
      the **Person** tag's `POST /v1/persons/batch`.


      ## Associations


      Use the dedicated sub-resource to manage links to other entities after
      creation:


      - `POST /v1/notes/{uuid}/associations` attaches a
      person/company/opportunity/file/task. Idempotent on duplicates — the
      existing row is returned.

      - `DELETE /v1/notes/{uuid}/associations/{association_uuid}` removes the
      link. `204 No Content` on success, `404 Not Found` if the association
      doesn't exist on the note.


      Associations can also be seeded at create-time via the `associations`
      array on `POST /v1/notes`.


      ## Semantic search


      `POST /v1/notes/search` performs hybrid vector + full-text search over
      tenant notes, grouped by source note with matching snippets. Behavior
      depends on `search_mode`:


      - **Direct/precise lookups** (default `recency`, or
      `historical`/`relevance`/`balanced`): fast, sub-second, ranked by raw
      hybrid search score. Use for narrow asks like 'what did I discuss with
      this person.'

      - **`comprehensive`**: for broad, ambiguous asks — e.g. 'give me everyone
      I've researched who fits this profile' — additionally reranks the full
      candidate set with a cross-encoder, scored against each note's associated
      person/company context (job title, company description, mentions) in
      addition to raw note text, so a note whose text never mentions a role or
      company type can still surface via its associated person/company record.
      This takes ~4-5s and has a small per-request cost — reach for it only when
      the query is genuinely broad, not for direct lookups.


      `limit` accepts 1-200 (default 10).
    name: Note
  - description: >-
      Operations for tenant tasks — actionable items with optional assignees,
      due dates, reminders, and entity associations.


      ## Visibility


      Tasks have two visibility modes:


      - `RING` (default) — visible to any active user in the tenant.

      - `PERSONAL` — visible only to the creator. PERSONAL tasks resolve `404
      Not Found` for other tenant users.


      ## Lifecycle


      - `POST /v1/tasks` creates a task. Assignees and associated entities are
      attached transactionally — partial failures are not possible.

      - `PUT /v1/tasks/{id}` updates fields. `due_date` and reminders can be
      cleared via the explicit `clear_due_date` / `clear_reminder` flags.

      - `DELETE /v1/tasks/{id}` soft-deletes a task. Visibility is enforced —
      PERSONAL tasks can only be deleted by their creator.


      ## Associations


      After creation, link tasks to other entities via the associations
      sub-resource:


      - `POST /v1/tasks/{id}/associations` attaches a
      person/company/opportunity/note/file. Visibility is preflighted — PERSONAL
      tasks belonging to other users return `404 Not Found`.

      - `DELETE /v1/tasks/{id}/associations/{association_uuid}` removes the
      link. `204 No Content` on success.
    name: Task
  - description: >-
      Tenant user management.


      Use `GET /v1/users` to list active users belonging to the API key's
      tenant. User UUIDs can then be passed in the `x-rings-user-id` header to
      enable per-user context on supported endpoints (recommended paths,
      activity history).
    name: Users
  - description: >-
      Calendar meetings for the authenticated user.


      `GET /v1/meetings` and `GET /v1/meetings/{activity_id}` return only
      meetings where that user is an internal calendar participant (the same
      scope as in-app meeting tools). User context is required:
      `x-rings-user-id` with a TENANT-scoped key, or a USER-scoped key.


      Meetings are calendar events (Google Calendar, Outlook, etc.) synced via
      connected email/calendar grants. They are stored as activity records with
      type `meeting`.


      ## Filtering


      - **Date range**: use `date_from` / `date_to` (ISO `YYYY-MM-DD`) to scope
      by meeting start time

      - **Participant**: use `person_uuid` or `company_uuid` to further narrow
      to meetings where that entity is also a participant

      - **Search**: use `search` (min 3 characters) to filter by title


      ## Participant fields


      | Field | Description |

      |---|---|

      | `kind` | Participant role: `ORGANIZER` or `PARTICIPANT` |

      | `status` | RSVP status: `accepted`, `declined`, `tentative`,
      `needsAction` |

      | `person_uuid` | Matched person UUID (if resolved) |

      | `company_uuid` | Matched company UUID (if resolved) |

      | `avatar_url` | Profile photo URL (if available) |

      | `is_current_user_participant` | Whether the requesting user is a
      participant (requires user context) |
    name: Meetings
  - description: >-
      AI-generated summaries for persons and companies.


      These endpoints return **cached/prior** summaries only — they do not
      trigger on-demand generation.


      ## Response shape


      | Field | Type | Description |

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

      | `entity_uuid` | string | UUID of the person or company |

      | `entity_type` | string | `"person"` or `"company"` |

      | `title` | string\|null | Summary title (e.g. "Jane Doe Summary") |

      | `bio` | string\|null | Person biography (person only, always null for
      companies) |

      | `sections[]` | array | Structured summary sections |

      | `sections[].heading` | string | Section heading |

      | `sections[].content` | string | Section content |

      | `generated_at` | string\|null | ISO-8601 timestamp of generation, or
      `null` |


      When no cached summary is available the response is still `200 OK` with
      `title` set to `<Entity Name> Summary`, `bio` null, `sections` empty, and
      `generated_at` null.
    name: AI Summary
  - description: >-
      Named collections of entities (e.g. "LP Feedback for Fund II"), and their
      membership.


      A list is single-kind — `kind` is one of `PERSON`, `COMPANY`, `NOTE`,
      `ACTIVITY`, `FILE`, `TASK`, `OPPORTUNITY`, never mixed. In practice
      `PERSON` and `COMPANY` are the common cases.


      ## Resolving a list


      `GET /v1/lists` searches by `name` (exact) or `search` (case-insensitive
      substring), optionally filtered by `kind`. Each result includes
      `entities_count`.


      ## Fetching membership


      `GET /v1/lists/{list_uuid}/entities` returns the paginated
      `entity_uuid`/`entity_kind` of each member. Returns `404` if the list
      doesn't exist or isn't accessible to the API key's tenant.


      ## Hydrating members


      These endpoints intentionally return UUIDs only. To get full records for a
      brief or export, pass the UUIDs to `GET /v1/companies?uuids=...` or `GET
      /v1/persons?uuids=...` (comma-separated), which already support batched
      lookup by UUID and return the same rich fields as their single-entity
      endpoints.


      ## Lifecycle


      - `POST /v1/lists` creates a list. List names are unique per tenant per
      `kind` — returns `409` if `name` is already in use for that `kind`. Pass
      `entity_uuids` to seed membership at creation time (each becomes a member
      with `entity_kind` = the list's `kind`).

      - `PUT /v1/lists/{list_uuid}` updates `name`, `description`, and/or
      `legacy_explorer_state` — only fields supplied are written. Membership is
      not affected by this endpoint. Only the list's owner or a tenant
      **ringmaster** may update it; other callers receive `404 Not Found` (the
      same response as a nonexistent list, to avoid leaking existence to
      non-owners).
    name: EntityList
  - description: >-
      Ring-wide and per-user relationships, ranked by relationship quality (RQ)
      / PathPower / last activity.


      Both endpoints are thin REST wrappers over precomputed parquet caches
      (MRR: My Ring Relationships) rather than live queries, so they return
      `503` while the precompute hasn't been built yet for the tenant (or user).


      - `GET /v1/relationships` — the tenant's external relationships (internal
      ring members excluded), refreshed every ~2h. Each item is one external
      person with their embedded primary company, RQ, PathPower, priority
      signals, AI scores, entity lists, and emails.

      - `GET /v1/relationships/mine` — the calling user's own relationships,
      sorted by that user's own `relationship_quality`, skipping the team
      aggregation/overlay enrichment the ring-wide endpoint does. Requires a
      user-bound API key (USER-scoped, or a TENANT-scoped key with
      `x-rings-user-id`) — returns `400` otherwise.


      ## Filtering and sorting


      Both accept `sort_by` (any MRR schema field, e.g. `relationship_quality`,
      `priority_score`, `last_activity_date`, `company_score`, `person_name`,
      `company_name`), `order`, and pagination. `relationship_quality` and
      `priority_score` also act as filters when passed as comma-separated
      integers (1-3); `company_score_from`/`company_score_to` bound by
      `company_score` with **exclusive** bounds (strictly greater-than /
      less-than, not >=/<=).
    name: Relationships
paths:
  /v1/opportunities:
    get:
      tags:
        - Opportunity
      summary: >-
        List opportunities in the caller's tenant with optional filtering and
        pagination.
      description: >-

        Returns a paginated list of opportunities visible to the tenant ring.


        Filter parameters (all optional):

        - name: Case-insensitive substring match on the opportunity's own name

        - search: Fuzzy search across name and associated person/company names

        - opportunity_type_uuid: Filter by opportunity type UUID (use GET
        /v1/opportunities
          to inspect `type.uuid` on existing records)
        - opportunity_stage_uuid: Filter by a single stage UUID

        - opportunity_stage_uuids: Comma-separated stage UUIDs (IN filter)

        - owner_user_uuid: Comma-separated user UUID(s); filters by owner

        - include_no_owner: Also include opportunities with no owner assigned

        - intro_person_uuid: Filter by the intro person's UUID

        - related_company_uuid / related_person_uuid: parent opportunities that
        have a
          sub-opportunity associated with this entity
        - parent_uuid: Return only sub-opportunities of this parent UUID

        - hierarchy_type: 'PARENT' or 'CHILD' (ignored if parent_uuid is set)

        - company_uuid / person_uuid: Comma-separated UUID(s); union of
        opportunities
          associated with any of them
        - value_from / value_to, probability_from / probability_to: inclusive
        range filters

        - updated_after / updated_before: ISO 8601 date/datetime range on
        updated_at

        - source_date_from / source_date_to: ISO 8601 dates, required together

        - last_activity_date_from / last_activity_date_to: ISO 8601 datetimes,
        required
          together

        Sort parameters:

        - sort_by: name | created_at | updated_at | value | weighted_value |
        probability |
          source_date | intro_date | last_activity_date | details | next_step | stage |
          owner | intro_person | days_in_stage | notes_and_files_count
        - order: asc | desc (default: asc)


        Pagination:

        - page: Page number (default: 1)

        - per_page: Results per page (default: 50)


        The response also includes `total_value`/`total_weighted_value`: sums of

        `value`/`weighted_value` across the full filtered set, not just the
        page.
      operationId: get_list_opportunities
      parameters:
        - description: Page number, 1-indexed. Clamped to >= 1.
          in: query
          name: page
          required: false
          schema:
            default: 1
            title: Page
            type: integer
        - description: >-
            Results per page. Clamped to the range 1-100 (values outside are
            silently capped, not rejected).
          in: query
          name: per_page
          required: false
          schema:
            default: 50
            title: Per Page
            type: integer
        - description: Case-insensitive substring match on opportunity name.
          in: query
          name: name
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Name
        - description: >-
            Filter by opportunity type UUID (call GET /v1/opportunity-types to
            discover valid values).
          in: query
          name: opportunity_type_uuid
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Opportunity Type Uuid
        - description: >-
            Filter by opportunity stage UUID (inspect stage.uuid on existing
            records).
          in: query
          name: opportunity_stage_uuid
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Opportunity Stage Uuid
        - description: >-
            Comma-separated list of opportunity stage UUIDs (IN filter, e.g. for
            'Diligence or later').
          in: query
          name: opportunity_stage_uuids
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Opportunity Stage Uuids
        - description: >-
            Fuzzy search across the opportunity name and its associated
            person/company names. Broader than `name`, which only matches the
            opportunity's own name field.
          in: query
          name: search
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Search
        - description: Comma-separated user UUID(s); filters by the opportunity owner.
          in: query
          name: owner_user_uuid
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Owner User Uuid
        - description: Include opportunities with no owner (owner is null).
          in: query
          name: include_no_owner
          required: false
          schema:
            default: false
            title: Include No Owner
            type: boolean
        - description: Filter by the intro person's UUID.
          in: query
          name: intro_person_uuid
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Intro Person Uuid
        - description: >-
            Return parent opportunities that have a sub-opportunity associated
            with this company UUID.
          in: query
          name: related_company_uuid
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Related Company Uuid
        - description: >-
            Return parent opportunities that have a sub-opportunity associated
            with this person UUID.
          in: query
          name: related_person_uuid
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Related Person Uuid
        - description: Return only the sub-opportunities of this parent opportunity UUID.
          in: query
          name: parent_uuid
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Parent Uuid
        - description: >-
            'PARENT' for top-level opportunities only, 'CHILD' for
            sub-opportunities only. Ignored when `parent_uuid` is set.
          in: query
          name: hierarchy_type
          required: false
          schema:
            anyOf:
              - enum:
                  - PARENT
                  - CHILD
                type: string
              - type: 'null'
            default: null
            title: Hierarchy Type
        - description: >-
            Comma-separated company UUID(s); returns opportunities associated
            with any of them.
          in: query
          name: company_uuid
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Company Uuid
        - description: >-
            Comma-separated person UUID(s); returns opportunities associated
            with any of them.
          in: query
          name: person_uuid
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Person Uuid
        - description: Minimum `value`, inclusive.
          in: query
          name: value_from
          required: false
          schema:
            anyOf:
              - type: integer
              - type: 'null'
            default: null
            title: Value From
        - description: Maximum `value`, inclusive.
          in: query
          name: value_to
          required: false
          schema:
            anyOf:
              - type: integer
              - type: 'null'
            default: null
            title: Value To
        - description: Minimum `probability`, inclusive.
          in: query
          name: probability_from
          required: false
          schema:
            anyOf:
              - type: integer
              - type: 'null'
            default: null
            title: Probability From
        - description: Maximum `probability`, inclusive.
          in: query
          name: probability_to
          required: false
          schema:
            anyOf:
              - type: integer
              - type: 'null'
            default: null
            title: Probability To
        - description: >-
            ISO 8601 date/datetime; only return opportunities updated at or
            after this time.
          in: query
          name: updated_after
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Updated After
        - description: >-
            ISO 8601 date/datetime; only return opportunities updated at or
            before this time.
          in: query
          name: updated_before
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Updated Before
        - description: >-
            ISO 8601 date (YYYY-MM-DD). Must be paired with `source_date_to` —
            both are required together.
          in: query
          name: source_date_from
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Source Date From
        - description: >-
            ISO 8601 date (YYYY-MM-DD). Must be paired with `source_date_from` —
            both are required together.
          in: query
          name: source_date_to
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Source Date To
        - description: >-
            ISO 8601 datetime. Must be paired with `last_activity_date_to` —
            both are required together.
          in: query
          name: last_activity_date_from
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Last Activity Date From
        - description: >-
            ISO 8601 datetime. Must be paired with `last_activity_date_from` —
            both are required together.
          in: query
          name: last_activity_date_to
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Last Activity Date To
        - description: >-
            Field to sort by. Valid values: 'name', 'created_at', 'updated_at',
            'value', 'weighted_value', 'probability', 'source_date',
            'intro_date', 'last_activity_date', 'details', 'next_step', 'stage'
            (pipeline stage order), 'owner' (by name), 'intro_person' (by name),
            'days_in_stage', 'notes_and_files_count'
          in: query
          name: sort_by
          required: false
          schema:
            anyOf:
              - enum:
                  - name
                  - created_at
                  - updated_at
                  - value
                  - weighted_value
                  - probability
                  - source_date
                  - intro_date
                  - last_activity_date
                  - details
                  - next_step
                  - stage
                  - owner
                  - intro_person
                  - days_in_stage
                  - notes_and_files_count
                type: string
              - type: 'null'
            default: null
            title: Sort By
        - description: 'Sort order. Valid values: ''asc'' (ascending) or ''desc'' (descending)'
          in: query
          name: order
          required: false
          schema:
            default: asc
            enum:
              - asc
              - desc
            title: Order
            type: string
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  custom_field_mapping:
                    anyOf:
                      - $ref: '#/components/schemas/CustomFieldMapping'
                      - type: 'null'
                    default: null
                  items:
                    items:
                      $ref: '#/components/schemas/OpportunityResponse'
                    title: Items
                    type: array
                  page:
                    title: Page
                    type: integer
                  per_page:
                    title: Per Page
                    type: integer
                  total:
                    title: Total
                    type: integer
                  total_value:
                    anyOf:
                      - type: integer
                      - type: 'null'
                    default: null
                    title: Total Value
                  total_weighted_value:
                    anyOf:
                      - type: integer
                      - type: 'null'
                    default: null
                    title: Total Weighted Value
                required:
                  - items
                  - page
                  - per_page
                  - total
                title: OpportunityListResponse
                type: object
          description: Paginated list of opportunities.
components:
  schemas:
    CustomFieldMapping:
      properties:
        fields:
          items:
            $ref: '#/components/schemas/CustomFieldDefinition'
          title: Fields
          type: array
        standard_key_to_uuid:
          anyOf:
            - additionalProperties:
                type: string
              type: object
            - type: 'null'
          default: null
          title: Standard Key To Uuid
        unresolved_keys:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          default: null
          title: Unresolved Keys
      required:
        - fields
      title: CustomFieldMapping
      type: object
    OpportunityResponse:
      properties:
        associations:
          anyOf:
            - items:
                $ref: '#/components/schemas/OpportunityAssociation'
              type: array
            - type: 'null'
          default: null
          title: Associations
        children_metadata:
          anyOf:
            - $ref: '#/components/schemas/OpportunityMetadata'
            - type: 'null'
          default: null
        company_last_activity_date:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Company Last Activity Date
        created_at:
          anyOf:
            - type: number
            - type: 'null'
          default: null
          title: Created At
        created_by:
          anyOf:
            - $ref: '#/components/schemas/RelatedPerson'
            - type: 'null'
          default: null
        custom_fields:
          anyOf:
            - items:
                additionalProperties: true
                type: object
              type: array
            - type: 'null'
          default: null
          title: Custom Fields
        days_in_stage:
          anyOf:
            - type: integer
            - type: 'null'
          default: null
          title: Days In Stage
        details:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Details
        intro_date:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Intro Date
        intro_person:
          anyOf:
            - $ref: '#/components/schemas/RelatedPerson'
            - type: 'null'
          default: null
        last_activity_date:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Last Activity Date
        name:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Name
        next_step:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Next Step
        notes_and_files_count:
          anyOf:
            - type: integer
            - type: 'null'
          default: null
          title: Notes And Files Count
        owner:
          anyOf:
            - $ref: '#/components/schemas/RelatedPerson'
            - type: 'null'
          default: null
        parent_name:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Parent Name
        parent_uuid:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Parent Uuid
        person_last_activity_date:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Person Last Activity Date
        probability:
          anyOf:
            - type: integer
            - type: 'null'
          default: null
          title: Probability
        search_string:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Search String
        source_date:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Source Date
        stage:
          anyOf:
            - $ref: '#/components/schemas/OpportunityStageOnRecord'
            - type: 'null'
          default: null
        type:
          anyOf:
            - $ref: '#/components/schemas/OpportunityTypeOnRecord'
            - type: 'null'
          default: null
        updated_at:
          anyOf:
            - type: number
            - type: 'null'
          default: null
          title: Updated At
        updated_by:
          anyOf:
            - $ref: '#/components/schemas/RelatedPerson'
            - type: 'null'
          default: null
        uuid:
          title: Uuid
          type: string
        value:
          anyOf:
            - type: integer
            - type: 'null'
          default: null
          title: Value
        weighted_value:
          anyOf:
            - type: integer
            - type: 'null'
          default: null
          title: Weighted Value
      required:
        - uuid
      title: OpportunityResponse
      type: object
    CustomFieldDefinition:
      properties:
        choices:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          default: null
          title: Choices
        key:
          title: Key
          type: string
        name:
          title: Name
          type: string
        type:
          title: Type
          type: string
        uuid:
          title: Uuid
          type: string
      required:
        - uuid
        - key
        - name
        - type
      title: CustomFieldDefinition
      type: object
    OpportunityAssociation:
      properties:
        association_type:
          anyOf:
            - type: string
            - type: 'null'
          title: Association Type
        company:
          anyOf:
            - $ref: '#/components/schemas/AssociatedCompany'
            - type: 'null'
          default: null
        context:
          anyOf:
            - type: string
            - type: 'null'
          title: Context
        created_at:
          anyOf:
            - type: number
            - type: 'null'
          title: Created At
        entity_type:
          enum:
            - PERSON
            - COMPANY
            - NOTE
            - FILE
            - TASK
            - OPPORTUNITY
          title: Entity Type
          type: string
        entity_uuid:
          title: Entity Uuid
          type: string
        last_activity_date:
          anyOf:
            - type: string
            - type: 'null'
          title: Last Activity Date
        person:
          anyOf:
            - $ref: '#/components/schemas/AssociatedPerson'
            - type: 'null'
          default: null
        updated_at:
          anyOf:
            - type: number
            - type: 'null'
          title: Updated At
        uuid:
          title: Uuid
          type: string
      required:
        - uuid
        - entity_uuid
        - entity_type
        - association_type
        - context
        - last_activity_date
        - created_at
        - updated_at
      title: OpportunityAssociation
      type: object
    OpportunityMetadata:
      properties:
        count:
          title: Count
          type: integer
        probability_sum:
          title: Probability Sum
          type: integer
        value_sum:
          title: Value Sum
          type: integer
        weighted_value_sum:
          title: Weighted Value Sum
          type: integer
      required:
        - count
        - weighted_value_sum
        - value_sum
        - probability_sum
      title: OpportunityMetadata
      type: object
    RelatedPerson:
      properties:
        logo_url:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Logo Url
        name:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Name
        type:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Type
        uuid:
          title: Uuid
          type: string
      required:
        - uuid
      title: RelatedPerson
      type: object
    OpportunityStageOnRecord:
      properties:
        name:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Name
        uuid:
          title: Uuid
          type: string
      required:
        - uuid
      title: OpportunityStageOnRecord
      type: object
    OpportunityTypeOnRecord:
      properties:
        is_hidden:
          anyOf:
            - type: boolean
            - type: 'null'
          default: null
          title: Is Hidden
        label:
          title: Label
          type: string
        label_plural:
          title: Label Plural
          type: string
        sub_label:
          title: Sub Label
          type: string
        sub_label_plural:
          title: Sub Label Plural
          type: string
        uuid:
          title: Uuid
          type: string
      required:
        - uuid
        - label
        - label_plural
        - sub_label
        - sub_label_plural
      title: OpportunityTypeOnRecord
      type: object
    AssociatedCompany:
      properties:
        last_activity_date:
          anyOf:
            - type: string
            - type: 'null'
          title: Last Activity Date
        logo_url:
          anyOf:
            - type: string
            - type: 'null'
          title: Logo Url
        name:
          anyOf:
            - type: string
            - type: 'null'
          title: Name
        type:
          anyOf:
            - type: string
            - type: 'null'
          title: Type
        uuid:
          title: Uuid
          type: string
      required:
        - uuid
        - name
        - logo_url
        - type
        - last_activity_date
      title: AssociatedCompany
      type: object
    AssociatedPerson:
      properties:
        email:
          anyOf:
            - type: string
            - type: 'null'
          title: Email
        last_activity_date:
          anyOf:
            - type: string
            - type: 'null'
          title: Last Activity Date
        logo_url:
          anyOf:
            - type: string
            - type: 'null'
          title: Logo Url
        name:
          anyOf:
            - type: string
            - type: 'null'
          title: Name
        type:
          anyOf:
            - type: string
            - type: 'null'
          title: Type
        uuid:
          title: Uuid
          type: string
      required:
        - uuid
        - name
        - email
        - logo_url
        - type
        - last_activity_date
      title: AssociatedPerson
      type: object
  securitySchemes:
    ApiKeyAuth:
      in: header
      name: x-api-key
      type: apiKey

````