> ## 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 persons

> 
Returns a paginated list of people visible to the tenant. All filter
parameters are optional — omitting all of them returns all persons.

Filter parameters:
- name: Case-insensitive substring match on person's display name
- email: Matches any of the person's emails (case/whitespace-insensitive)
- linkedin_url: Case-insensitive substring match on LinkedIn profile URL
- company_uuid: Matches persons whose current/primary company is this company UUID
- job_title: Case-insensitive substring match on job title
- modified_since: ISO 8601 timestamp — return only persons modified at or after
  this time (e.g. '2025-01-01T00:00:00Z')

Sort parameters:
- sort_by: name | last_activity_date (default: unsorted)
- order: asc | desc (default: asc)

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



## OpenAPI

````yaml GET /v1/persons
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/persons:
    get:
      tags:
        - Person
      summary: >-
        List persons in the caller's tenant with optional filtering and
        pagination.
      description: >-

        Returns a paginated list of people visible to the tenant. All filter

        parameters are optional — omitting all of them returns all persons.


        Filter parameters:

        - name: Case-insensitive substring match on person's display name

        - email: Matches any of the person's emails
        (case/whitespace-insensitive)

        - linkedin_url: Case-insensitive substring match on LinkedIn profile URL

        - company_uuid: Matches persons whose current/primary company is this
        company UUID

        - job_title: Case-insensitive substring match on job title

        - modified_since: ISO 8601 timestamp — return only persons modified at
        or after
          this time (e.g. '2025-01-01T00:00:00Z')

        Sort parameters:

        - sort_by: name | last_activity_date (default: unsorted)

        - order: asc | desc (default: asc)


        Pagination:

        - page: Page number (default: 1)

        - per_page: Results per page, max 100 (default: 50)
      operationId: get_list_persons
      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
        - in: query
          name: name
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Name
        - in: query
          name: email
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Email
        - in: query
          name: linkedin_url
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Linkedin Url
        - description: >-
            Filter to persons whose primary company affiliation is this company
            UUID. Same source as the response's `current_company.uuid`
            (highest-priority `PrimaryAffiliation`).
          in: query
          name: company_uuid
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Company Uuid
        - description: >-
            Filter to persons whose current job title contains this text. Backed
            by a recently-added column still being backfilled for existing
            records, so coverage may be incomplete for a while.
          in: query
          name: job_title
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Job Title
        - description: >-
            Return only persons modified at or after this ISO 8601 timestamp
            (e.g. '2025-01-01T00:00:00Z'). Filtered on the `rings_updated_at`
            field which tracks the last time Rings updated the record.
          in: query
          name: modified_since
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Modified Since
        - description: 'Field to sort by. Valid values: ''name'', ''last_activity_date'''
          in: query
          name: sort_by
          required: false
          schema:
            anyOf:
              - enum:
                  - name
                  - last_activity_date
                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
        - description: >-
            Case-insensitive substring match on the person's current job title
            (from the is_current=true employment row).
          in: query
          name: current_job_title
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Current Job Title
        - description: >-
            Case-insensitive substring match on the person's current company
            name.
          in: query
          name: current_company_name
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Current Company Name
        - description: >-
            Exact match on the person's current company domain (e.g.
            'acme.com').
          in: query
          name: current_company_domain
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Current Company Domain
        - description: >-
            ISO 8601 timestamp — filter to persons whose current role started at
            or after this date (job_changed_at >= value).
          in: query
          name: job_changed_since
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Job Changed Since
        - description: >-
            ISO 8601 timestamp — filter to persons whose current role started at
            or before this date (job_changed_at <= value).
          in: query
          name: job_changed_before
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Job Changed Before
        - description: >-
            ISO 8601 timestamp — filter to persons whose most-recent prior job
            ended at or after this date.
          in: query
          name: previous_job_ended_since
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Previous Job Ended Since
        - description: >-
            ISO 8601 timestamp — filter to persons whose most-recent prior job
            ended at or before this date.
          in: query
          name: previous_job_ended_before
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Previous Job Ended Before
        - description: >-
            Comma-separated list of person UUIDs to fetch. When set, only these
            persons are returned (subject to other filters).
          in: query
          name: uuids
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            default: null
            title: Uuids
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  items:
                    items:
                      $ref: '#/components/schemas/PersonResponse'
                    title: Items
                    type: array
                  page:
                    title: Page
                    type: integer
                  per_page:
                    title: Per Page
                    type: integer
                  total:
                    title: Total
                    type: integer
                required:
                  - items
                  - page
                  - per_page
                  - total
                title: PersonListResponse
                type: object
          description: Paginated list of persons.
components:
  schemas:
    PersonResponse:
      properties:
        city:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: City
        company_name:
          anyOf:
            - type: string
            - type: 'null'
          title: Company Name
        company_pathpower:
          anyOf:
            - $ref: '#/components/schemas/PathPowerMetrics'
            - type: 'null'
          default: null
        country:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Country
        current_company:
          anyOf:
            - $ref: '#/components/schemas/CurrentCompany'
            - type: 'null'
          default: null
        current_company_domain:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Domain of the company on the person's current employment row.
            Filterable via ?current_company_domain=.
          title: Current Company Domain
        current_company_name:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Name of the company on the person's current (is_current) employment
            row. Filterable via ?current_company_name=.
          title: Current Company Name
        current_job_title:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Current job title from the LiveData-enriched employment history
            ledger. Filterable via ?current_job_title=.
          title: Current Job Title
        description:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Description
        email:
          anyOf:
            - type: string
            - type: 'null'
          title: Email
        email_3:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Email 3
        email_3_last_seen:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Email 3 Last Seen
        email_4:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Email 4
        email_4_last_seen:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Email 4 Last Seen
        email_5:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Email 5
        email_5_last_seen:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Email 5 Last Seen
        email_last_seen:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Email Last Seen
        entity_lists:
          anyOf:
            - items:
                $ref: '#/components/schemas/EntityListMembership'
              type: array
            - type: 'null'
          default: null
          title: Entity Lists
        facebook_url:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Facebook Url
        investor_types:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          default: null
          title: Investor Types
        is_primary_company_recommended:
          anyOf:
            - type: boolean
            - type: 'null'
          default: null
          title: Is Primary Company Recommended
        job_changed_at:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            ISO 8601 timestamp of when the person moved into their current role
            (started_at of the is_current row). Filterable via
            ?job_changed_since / ?job_changed_before.
          title: Job Changed At
        job_title:
          anyOf:
            - type: string
            - type: 'null'
          title: Job Title
        last_activity:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Last Activity
        last_activity_date:
          anyOf:
            - type: string
            - type: 'null'
          title: Last Activity Date
        last_contact_at:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Most recent tenant-wide contact timestamp, aggregated across all
            activity types. Alias of `last_activity_date`; both fields read from
            the same `ActivityDateByEntity` column that powers the list/detail
            endpoints.
          title: Last Contact At
        linkedin_url:
          anyOf:
            - type: string
            - type: 'null'
          title: Linkedin Url
        logo_url:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Logo Url
        my_next_meeting_at:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            ISO 8601 timestamp of the earliest future calendar event involving
            this person where the calling user (x-rings-user-id) is a
            participant. null when no user context is provided.
          title: My Next Meeting At
        my_next_meeting_title:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Title of the per-user next meeting. null when no user context is
            provided.
          title: My Next Meeting Title
        name:
          anyOf:
            - type: string
            - type: 'null'
          title: Name
        next_meeting_at:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            ISO 8601 timestamp of the earliest future calendar event involving
            this person (tenant-wide). Source: Activity.kind=EVENT, start_date
            >= now(), non-cancelled, non-deleted, non-hidden. Listener-driven
            with hourly recompute fallback.
          title: Next Meeting At
        next_meeting_title:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: Title of the tenant-wide next meeting.
          title: Next Meeting Title
        next_meeting_with_user_uuid:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            UsersPrivate.uuid of the internal user attending the tenant-wide
            next meeting (prefers organizer).
          title: Next Meeting With User Uuid
        pathpower:
          anyOf:
            - $ref: '#/components/schemas/PathPowerMetrics'
            - type: 'null'
          default: null
        phone_numbers:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          default: null
          title: Phone Numbers
        previous_job_ended_at:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            ISO 8601 timestamp of the most-recent prior job's end date (ended_at
            of the most-recent non-current row). Filterable via
            ?previous_job_ended_since / ?previous_job_ended_before.
          title: Previous Job Ended At
        priority_management:
          anyOf:
            - $ref: '#/components/schemas/PriorityManagement'
            - type: 'null'
          default: null
        secondary_email:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Secondary Email
        secondary_email_last_seen:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Secondary Email Last Seen
        state:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: State
        strongest_relationships:
          anyOf:
            - items:
                $ref: '#/components/schemas/StrongestRelationship'
              type: array
            - type: 'null'
          default: null
          description: >-
            Up to two tenant internal users with the strongest relationship to
            this person, ranked by `priority_management.rq_pretty` (desc).
            Precomputed every ~3 hours; `null` when no qualifying signals exist.
          title: Strongest Relationships
        twitter_url:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Twitter Url
        uuid:
          title: Uuid
          type: string
      required:
        - uuid
        - name
        - email
        - company_name
        - job_title
        - linkedin_url
        - last_activity_date
      title: PersonResponse
      type: object
    PathPowerMetrics:
      properties:
        meta:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          default: null
          title: Meta
        score:
          anyOf:
            - type: number
            - type: 'null'
          default: null
          title: Score
        strength_label:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Strength Label
      title: PathPowerMetrics
      type: object
    CurrentCompany:
      properties:
        company_name:
          anyOf:
            - type: string
            - type: 'null'
          title: Company Name
        job_type:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Job Type
        logo_url:
          anyOf:
            - type: string
            - type: 'null'
          title: Logo Url
        source:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Source
        uuid:
          anyOf:
            - type: string
            - type: 'null'
          title: Uuid
      required:
        - uuid
        - company_name
        - logo_url
      title: CurrentCompany
      type: object
    EntityListMembership:
      properties:
        name:
          title: Name
          type: string
        uuid:
          title: Uuid
          type: string
      required:
        - uuid
        - name
      title: EntityListMembership
      type: object
    PriorityManagement:
      properties:
        rq:
          anyOf:
            - type: number
            - type: 'null'
          default: null
          title: Rq
        rq_manual:
          anyOf:
            - type: number
            - type: 'null'
          default: null
          title: Rq Manual
        rq_math:
          anyOf:
            - type: number
            - type: 'null'
          default: null
          title: Rq Math
      title: PriorityManagement
      type: object
    StrongestRelationship:
      properties:
        internal_user_person_uuid:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Person UUID for the internal user, usable as the `{uuid}` path
            parameter on other person endpoints.
          title: Internal User Person Uuid
        internal_user_uuid:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: UUID of the internal tenant user. Matches `UsersPrivate.uuid`.
          title: Internal User Uuid
        last_engaged_at:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            ISO 8601 timestamp of the most recent all-time activity between this
            internal user and the subject entity, sourced from
            `ActivityStatsByEntity`. May lag behind true activity while the
            activity-stats pipeline is in remediation.
          title: Last Engaged At
        name:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: Display name of the internal user.
          title: Name
        path_power_score:
          anyOf:
            - type: number
            - type: 'null'
          default: null
          description: >-
            Strength of the relationship, sourced from
            `priority_management.rq_pretty`. Higher is stronger. The existing
            `pathpower.score` field remains the preferred numeric score for the
            person/company itself; this field reflects the specific internal
            user's relationship.
          title: Path Power Score
      title: StrongestRelationship
      type: object
  securitySchemes:
    ApiKeyAuth:
      in: header
      name: x-api-key
      type: apiKey

````