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

# StartPersonCallAPI connects a person to a lead: Erdo rings the person's own


> phone from one of the organization's voice agent numbers, and when they answer and press 1 it dials the lead and bridges the two. The lead sees the organization's number.

It has no MCP tool and no CLI verb, and that is the point rather than an omission. Every other capability on this gateway completes on its own; this one rings a phone that a specific human being has to be holding, and answer, within about thirty seconds. An agent or a script that "placed a call" would have started something only a person can finish — so the only caller that makes sense is a product surface with a person looking at it, which reaches Erdo over REST.

The refusals are values, not prose: \`refused\` with a \`reason\` the caller branches on (the number is not this organization's, the lead opted out, that person is already on a call, the provider would not dial the destination). A successful response echoes both numbers normalised to E.164 with their countries, because a number typed without a country code has just been read as US/Canada and the person placing the call is the only one who can catch that.




## OpenAPI

````yaml /api/openapi.json post /v1/voice/person-calls
openapi: 3.0.0
info:
  title: Erdo API
  description: >-
    Erdo's REST API: query and write datasets, run agents, manage threads,
    integrations, pages, evals, workstreams, experiments, and bounded outreach.
    Authenticate with a Bearer API key (erdo_api_...) or scoped token
    (erdo_token_...).
  version: '2026-09-22'
servers:
  - url: https://api.erdo.ai
    description: Production
security:
  - bearerAuth: []
paths:
  /v1/voice/person-calls:
    post:
      summary: >
        StartPersonCallAPI connects a person to a lead: Erdo rings the person's
        own
      description: >
        phone from one of the organization's voice agent numbers, and when they
        answer and press 1 it dials the lead and bridges the two. The lead sees
        the organization's number.


        It has no MCP tool and no CLI verb, and that is the point rather than an
        omission. Every other capability on this gateway completes on its own;
        this one rings a phone that a specific human being has to be holding,
        and answer, within about thirty seconds. An agent or a script that
        "placed a call" would have started something only a person can finish —
        so the only caller that makes sense is a product surface with a person
        looking at it, which reaches Erdo over REST.


        The refusals are values, not prose: \`refused\` with a \`reason\` the
        caller branches on (the number is not this organization's, the lead
        opted out, that person is already on a call, the provider would not dial
        the destination). A successful response echoes both numbers normalised
        to E.164 with their countries, because a number typed without a country
        code has just been read as US/Canada and the person placing the call is
        the only one who can catch that.
      operationId: POST:mcp.StartPersonCallAPI
      requestBody:
        content:
          application/json:
            schema:
              properties:
                canonical_lead_id:
                  description: >
                    22-character reference form. Required: the lead's timeline
                    finds calls by this id, and a call that could not appear on
                    it would defeat the point.
                  title: >
                    CanonicalLeadID is the lead this call belongs to, in either
                    the UUID or the
                  type: string
                from_number:
                  description: >
                    number the lead will see. It must be one Erdo manages inside
                    the organization's Twilio subaccount.
                  title: >
                    FromNumber is the organization's own agent number to call
                    from, and the
                  type: string
                person_phone:
                  description: >
                    record — the provider already holds it for the duration of
                    the call, and keeping a copy of an employee's mobile beside
                    every lead is not something this feature needs.
                  title: >
                    PersonPhone is the phone Erdo rings first. It is never
                    stored on the call
                  type: string
                placed_by:
                  $ref: '#/components/schemas/voice.PersonCallPlacedBy'
                prompt_language:
                  description: >
                    default), "es" or "pt". Anything else is refused rather than
                    silently spoken in English at somebody who does not speak
                    it.
                  title: >
                    PromptLanguage selects the language of the press-1 prompt:
                    "en" (the
                  type: string
                recipient_name:
                  description: |
                    call Maria Lopez") and shown on the call record.
                  title: >
                    RecipientName is the lead's name, spoken in the press-1
                    prompt ("Press 1 to
                  type: string
                to_number:
                  description: |
                    it is normalised to E.164 and echoed back.
                  title: >
                    ToNumber is the lead's phone number, as it is stored — free
                    text is fine,
                  type: string
              type: object
              required:
                - from_number
                - to_number
                - canonical_lead_id
                - placed_by
                - person_phone
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  call_id:
                    description: |
                      empty when the call was refused.
                    title: >
                      CallID is the record this call is kept under — the id to
                      read it back by,
                    type: string
                  from_number:
                    title: >
                      FromNumber is the organization's number the lead will see,
                      in E.164.
                    type: string
                  message:
                    type: string
                  person_country:
                    type: string
                  person_phone:
                    title: >
                      PersonPhone / PersonCountry are the same for the phone
                      Erdo rings first.
                    type: string
                  prompt_language:
                    title: >
                      PromptLanguage is the language the press-1 prompt will be
                      spoken in.
                    type: string
                  reason:
                    type: string
                  refused:
                    description: |
                      PersonCallRefused\* values and Message says it in words.
                    title: |
                      Refused says the call was not placed; Reason is one of the
                    type: boolean
                  to_country:
                    type: string
                  to_number:
                    description: |
                      country that number belongs to.
                    title: >
                      ToNumber / ToCountry are the lead's number as Erdo will
                      dial it and the ISO
                    type: string
                type: object
          description: Success response
        default:
          $ref: '#/components/responses/APIError'
components:
  schemas:
    voice.PersonCallPlacedBy:
      description: >
        terms. Ref is whatever stable identifier that surface has for them
        (Maurice sends its Clerk user id); Erdo never resolves it, it only keys
        the one-live- call-per-person rule on it and shows Name beside the call.
      properties:
        name:
          type: string
        ref:
          type: string
      title: |
        PersonCallPlacedBy names the human placing the call, in the CALLER's own
      type: object
  responses:
    APIError:
      content:
        application/json:
          schema:
            externalDocs:
              url: https://pkg.go.dev/encore.dev/beta/errs#Error
            properties:
              code:
                description: Error code
                example: not_found
                externalDocs:
                  url: https://pkg.go.dev/encore.dev/beta/errs#ErrCode
                type: string
              details:
                description: Error details
                type: object
              message:
                description: Error message
                type: string
            title: APIError
            type: object
      description: Error response
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: An Erdo API key (erdo_api_...) or scoped token (erdo_token_...).

````