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

# Resolve conversation counterpart

> Turn what a user pasted (a linkedin.com/in/ link, a Sales Navigator or Recruiter link, a bare slug or a raw URN) into the identity a thread can be born on: the canonical member id plus the other axes the answer carried, and the playtables person it links to. Call it before send_message when you only have a link.

The ladder runs cheapest first and stops at the first rung that answers: the normalizer names the one axis in the target; a URN decodes to the member id with no wire call; a slug is looked up against the team's playtables people, the sender profile's first-degree connections and the data corpus, and only then against a lite profile read, which spends one enrichment slot and can answer 429 with retry_after. result.resolution.source names the rung (free or paid).

People are never created here: a null person_sid is a normal answer, the thread stays unlinked. What a wire rung learned is written onto an existing person fill-if-empty, so the next resolve is free. No LinkedIn URL is returned or stored: the axes travel, a screen rebuilds a link from ln_nickname. 422 when the target is not a profile target, the URN will not decode, the profile stays unresolvable, or the sender profile has no LinkedIn account. A rung nobody could answer is a pause, never a verdict, and no rung behind it runs: 429 gtm_busy, 403 gtm_access_lost or gtm_scope_missing, 503 gtm_unavailable, gtm_bridge_unavailable or playtables_unavailable: try again later.

Contract:
- MCP tool `resolve_conversation_counterpart`, registry package `mcp.unibox/conversations`, mount `unibox.inbox`.
- Operation `action`, response envelope `action`.
- Flags: none.



## OpenAPI

````yaml /api-reference/unibox/openapi.yaml post /api/conversations/resolve-counterpart
openapi: 3.0.3
info:
  title: 'GetSales public contract: gs.service.unibox'
  description: >-
    The team inbox and the AI SDR: every LinkedIn and email thread in one place
    (conversations, messages, the timeline events), the manual tasks a thread
    spawns, the sender profiles the team speaks through with their LinkedIn
    account and mailboxes, and the one agent per team with its scenarios, plans
    and runs.


    GENERATED. This document is projected from the Zod MCP tool registry in
    `product/mcp/gs.mcp` (one tool per public endpoint, 1:1). Do not edit it by
    hand; edit the tool definition and regenerate with `pnpm openapi:public`.


    Surface: the public `/api` contract of `gs.service.unibox`, 125 operations.
    This is the only OpenAPI document the platform publishes. Internal
    (`/internal`) and health endpoints are deliberately absent: they are not
    part of any contract, they can change without notice, and the service source
    is their only description.


    Conventions:

    - Auth is a bearer JWT, optionally narrowed by the `Team-SID` header.

    - Every success body is an MCP envelope: `success: true` plus one typed
    `operation` shape (`search`, `get`, `create`, `update`, `delete`, `metrics`,
    `group_by`, `action`), and a `meta` block with `trace_id` for support.

    - Every failure is the same `McpError` envelope with a code from a fixed
    16-code taxonomy, so a client maps errors once.

    - Lists page with `page_size` (0 to 500, default 50) plus an opaque forward
    `cursor`; `page_size: 0` returns counts only.

    - On `GET` and `DELETE`, object-valued query parameters (`filter`, `sort`)
    travel as JSON text and array-valued ones repeat as `name[]=value`.

    - The MCP-only `_meta` field (usage analytics) never reaches the backend and
    is not part of this contract.
  version: '1.0'
  contact:
    name: GetSales
    url: https://getsales.io
    email: support@getsales.io
  license:
    name: Proprietary
    url: https://getsales.io/terms
servers:
  - url: https://beta.getsales.io/unibox/v1
    description: >-
      Production (the gateway path on the beta ring; the origin is provisioned
      per DEPLOY_MAP.md)
security:
  - BearerJwt: []
    TeamSid: []
tags:
  - name: agent_answers
    description: >-
      Registry package `mcp.unibox/agent_answers`, served on MCP mount
      `unibox.knowledge`.
  - name: agent_conversation_uploads
    description: >-
      Registry package `mcp.unibox/agent_conversation_uploads`, served on MCP
      mount `unibox.agent-memory`.
  - name: agent_examples
    description: >-
      Registry package `mcp.unibox/agent_examples`, served on MCP mount
      `unibox.agent-memory`.
  - name: agent_hints
    description: >-
      Registry package `mcp.unibox/agent_hints`, served on MCP mount
      `unibox.agent-memory`.
  - name: agent_plans
    description: >-
      Registry package `mcp.unibox/agent_plans`, served on MCP mount
      `unibox.agent`.
  - name: agent_runs
    description: >-
      Registry package `mcp.unibox/agent_runs`, served on MCP mount
      `unibox.agent-memory`.
  - name: agent_scenarios
    description: >-
      Registry package `mcp.unibox/agent_scenarios`, served on MCP mount
      `unibox.agent`.
  - name: agent_source_parses
    description: >-
      Registry package `mcp.unibox/agent_source_parses`, served on MCP mount
      `unibox.knowledge`.
  - name: agent_sources
    description: >-
      Registry package `mcp.unibox/agent_sources`, served on MCP mount
      `unibox.knowledge`.
  - name: agent_tests
    description: >-
      Registry package `mcp.unibox/agent_tests`, served on MCP mount
      `unibox.agent-memory`.
  - name: agents
    description: >-
      Registry package `mcp.unibox/agents`, served on MCP mount
      `unibox.website`.
  - name: conversation_events
    description: >-
      Registry package `mcp.unibox/conversation_events`, served on MCP mount
      `unibox.inbox`.
  - name: conversations
    description: >-
      Registry package `mcp.unibox/conversations`, served on MCP mount
      `unibox.inbox`.
  - name: messages
    description: >-
      Registry package `mcp.unibox/messages`, served on MCP mount
      `unibox.inbox`.
  - name: sender_profiles
    description: >-
      Registry package `mcp.unibox/sender_profiles`, served on MCP mount
      `unibox.sender-profiles`.
  - name: tasks
    description: Registry package `mcp.unibox/tasks`, served on MCP mount `unibox.inbox`.
  - name: timeline
    description: >-
      Registry package `mcp.unibox/timeline`, served on MCP mount
      `unibox.inbox`.
paths:
  /api/conversations/resolve-counterpart:
    post:
      tags:
        - conversations
      summary: Resolve conversation counterpart
      description: >-
        Turn what a user pasted (a linkedin.com/in/ link, a Sales Navigator or
        Recruiter link, a bare slug or a raw URN) into the identity a thread can
        be born on: the canonical member id plus the other axes the answer
        carried, and the playtables person it links to. Call it before
        send_message when you only have a link.


        The ladder runs cheapest first and stops at the first rung that answers:
        the normalizer names the one axis in the target; a URN decodes to the
        member id with no wire call; a slug is looked up against the team's
        playtables people, the sender profile's first-degree connections and the
        data corpus, and only then against a lite profile read, which spends one
        enrichment slot and can answer 429 with retry_after.
        result.resolution.source names the rung (free or paid).


        People are never created here: a null person_sid is a normal answer, the
        thread stays unlinked. What a wire rung learned is written onto an
        existing person fill-if-empty, so the next resolve is free. No LinkedIn
        URL is returned or stored: the axes travel, a screen rebuilds a link
        from ln_nickname. 422 when the target is not a profile target, the URN
        will not decode, the profile stays unresolvable, or the sender profile
        has no LinkedIn account. A rung nobody could answer is a pause, never a
        verdict, and no rung behind it runs: 429 gtm_busy, 403 gtm_access_lost
        or gtm_scope_missing, 503 gtm_unavailable, gtm_bridge_unavailable or
        playtables_unavailable: try again later.


        Contract:

        - MCP tool `resolve_conversation_counterpart`, registry package
        `mcp.unibox/conversations`, mount `unibox.inbox`.

        - Operation `action`, response envelope `action`.

        - Flags: none.
      operationId: resolve_conversation_counterpart
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ResolveConversationCounterpartRequest'
      responses:
        '200':
          description: '`action` success envelope.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResolveConversationCounterpartResponse'
        4XX:
          $ref: '#/components/responses/McpClientError'
        5XX:
          $ref: '#/components/responses/McpServerError'
components:
  schemas:
    ResolveConversationCounterpartRequest:
      type: object
      description: Request body of `resolve_conversation_counterpart`.
      properties:
        sender_profile_sid:
          type: string
          minLength: 18
          maxLength: 18
          pattern: ^ub_sp_
          description: >-
            The sender profile that would speak. It must have a LinkedIn account
            attached, else 422 sender_profile_has_no_linkedin_account; its
            connections and its enrichment slots are what the ladder spends.
        target:
          type: string
          minLength: 2
          maxLength: 512
          description: >-
            What the user pasted: a linkedin.com/in/ link, a Sales Navigator or
            Recruiter profile link, a bare vanity slug, or a raw URN. Anything
            the normalizer cannot read as ONE profile axis answers 422
            not_a_linkedin_profile.
      required:
        - sender_profile_sid
        - target
    ResolveConversationCounterpartResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        operation:
          type: string
          enum:
            - action
        action:
          type: string
          description: kebab-case verb; matches the route segment.
        item: {}
        result:
          type: object
          properties:
            resolution:
              type: object
              properties:
                ln_member_id:
                  type: string
                  description: >-
                    The canonical LinkedIn member id, the axis a new thread is
                    born on. Always present on a success.
                source:
                  type: string
                  enum:
                    - decoded
                    - playtables
                    - connections
                    - corpus
                    - lite_profile
                  description: >-
                    Which rung answered: decoded (a URN was pasted, no wire
                    call), playtables (a person already knew the slug),
                    connections (the sender profile's first-degree connections),
                    corpus (the gtm.service.data person corpus), lite_profile
                    (one enrichment slot on the sender profile).
                ln_id:
                  type: string
                  nullable: true
                  description: >-
                    The raw LinkedIn profile URN, when the target carried it or
                    a wire rung learned it.
                sn_id:
                  type: string
                  nullable: true
                  description: The raw Sales Navigator URN, same rule.
                recruiter_id:
                  type: string
                  nullable: true
                  description: The raw Recruiter URN, same rule.
                ln_nickname:
                  type: string
                  nullable: true
                  description: >-
                    The vanity slug, lowercased. Rebuild a profile link from it
                    if you need to show one; no URL is returned or stored.
                full_name:
                  type: string
                  nullable: true
                  description: >-
                    Display name, when the rung that answered carried one
                    (connections, corpus, lite_profile).
                person_sid:
                  type: string
                  nullable: true
                  description: >-
                    The playtables person this counterpart links to (cr_pp_...),
                    or null when the team holds none. People are never created
                    here.
              required:
                - ln_member_id
                - source
                - ln_id
                - sn_id
                - recruiter_id
                - ln_nickname
                - full_name
                - person_sid
              description: The resolved counterpart. Identity axes only.
          required:
            - resolution
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: >-
                The team this call ran in (the token team, or the team_sid
                override). Null when unauthenticated; absent from pre-2026-08-20
                backends.
            actor_type:
              type: string
              nullable: true
              description: >-
                user | agent | api_key | system. Null when unauthenticated;
                absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - operation
        - action
        - item
        - result
        - meta
    McpError:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - false
        error:
          type: object
          properties:
            code:
              type: string
              enum:
                - validation_failed
                - nothing_to_update
                - not_found
                - relation_not_found
                - invalid_transition
                - limit_exceeded
                - payment_required
                - duplicate_rejected
                - conflict
                - delete_blocked
                - unauthorized
                - forbidden
                - rate_limited
                - internal_error
                - service_unavailable
                - not_implemented
            message:
              type: string
            recoverable:
              type: boolean
            suggestion:
              type: string
            field_errors:
              type: object
              additionalProperties:
                type: array
                items:
                  type: object
                  properties:
                    rule:
                      type: string
                    message:
                      type: string
                  required:
                    - rule
                    - message
            blockers:
              type: array
              items:
                type: object
                properties:
                  type:
                    type: string
                    description: >-
                      Machine-readable blocker type (active_flow, pending_tasks,
                      …).
                  severity:
                    type: string
                    enum:
                      - hard
                      - soft
                    description: >-
                      hard = external action required; soft = acknowledge is
                      enough.
                  description:
                    type: string
                  entity_sid:
                    type: string
                    nullable: true
                  count:
                    type: integer
                  resolution:
                    type: string
                    description: 'Hard: tool name to call. Soft: code for acknowledge[].'
                  resolution_hint:
                    type: string
                required:
                  - type
                  - severity
                  - description
                  - entity_sid
                  - resolution
                  - resolution_hint
            context:
              type: object
              additionalProperties: {}
          required:
            - code
            - message
            - recoverable
        meta:
          type: object
          properties:
            trace_id:
              type: string
              description: UUID v7; same 128-bit value as the X-Trace-Id header.
            span_id:
              type: string
              pattern: ^[0-9a-f]{16}$
              description: 16 hex chars, root span of this request.
            timestamp:
              type: string
              description: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
            duration_ms:
              type: integer
              minimum: 0
              description: Server-side wall clock.
            team_sid:
              type: string
              nullable: true
              description: >-
                The team this call ran in (the token team, or the team_sid
                override). Null when unauthenticated; absent from pre-2026-08-20
                backends.
            actor_type:
              type: string
              nullable: true
              description: >-
                user | agent | api_key | system. Null when unauthenticated;
                absent from pre-2026-08-20 backends.
          required:
            - trace_id
            - span_id
            - timestamp
            - duration_ms
      required:
        - success
        - error
  responses:
    McpClientError:
      description: >-
        MCP error envelope. `error.code` is one of validation_failed,
        nothing_to_update, not_found, relation_not_found, invalid_transition,
        limit_exceeded, payment_required, duplicate_rejected, conflict,
        delete_blocked, unauthorized, forbidden, rate_limited, not_implemented.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/McpError'
    McpServerError:
      description: >-
        MCP error envelope with `error.code` internal_error or
        service_unavailable.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/McpError'
  securitySchemes:
    BearerJwt:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        Access token issued by gs.service.id. Its `access_identity` claim
        carries `team_sid`, `actor_sid` and `actor_type`, and that team scope is
        authoritative.
    TeamSid:
      type: apiKey
      in: header
      name: Team-SID
      description: >-
        Team scope for tokens that do not carry one. Ignored when the token
        already names a team.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.