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

# SIP 연동

> vox.ai 외부에서 보유한 custom SIP 전화번호를 등록합니다. 고객이 관리하는 SIP trunk로 라우팅할 번호에 사용합니다.



## OpenAPI

````yaml /api-reference/v3/openapi.json post /telephone-numbers/register
openapi: 3.1.0
info:
  title: vox.ai API
  description: >
    vox.ai API v3


    ### v3 공개 계약 규칙


    - 인증은 `Authorization: Bearer <token>` 헤더를 사용합니다. 조직 API 키를 Bearer 토큰으로
    전달합니다.

    - 요청과 응답 필드는 기본적으로 `snake_case`를 사용합니다.

    - `agent.data`는 에이전트 레지스트리와 호환되어야 하므로 `callSettings`, `toolIds`,
    `builtInTools`, `presetDynamicVariables` 같은 camelCase 필드를 유지합니다.

    - `_at`으로 끝나는 타임스탬프는 unix milliseconds입니다. 일부 입력값은 호환성을 위해 10~11자리 unix
    seconds도 허용하고 milliseconds로 정규화합니다.

    - 캠페인 통화 가능 시간은 분 단위 정수(`start_min` / `end_min`)를 사용합니다. 알림 스케줄은 `HH:MM`
    문자열(`start_time` / `end_time`)을 사용합니다.

    - 응답 객체 자신의 식별자는 `id`입니다. 다른 리소스를 참조하는 필드와 path parameter는 `agent_id`,
    `call_id`, `telephone_line_id`처럼 명시적인 이름을 사용합니다.

    - 실패 응답은 `{ "error": { "code", "message", "details" } }` 형태입니다. 가능한 경우
    `details.field`, `details.reason`, `details.allowed_values`를 함께 제공합니다.
  version: 3.0.0
servers:
  - url: https://client-api.tryvox.co/v3
    description: 운영
security: []
paths:
  /telephone-numbers/register:
    post:
      tags:
        - Telephone Numbers
      summary: SIP 연동
      description: >-
        vox.ai 외부에서 보유한 custom SIP 전화번호를 등록합니다. 고객이 관리하는 SIP trunk로 라우팅할 번호에
        사용합니다.
      operationId: registerTelephoneNumber
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RegisterNumberRequest'
            examples:
              with_basic_auth:
                summary: Basic 인증이 필요한 SIP trunk
                value:
                  number: '07011112222'
                  address: sip:trunk.example.com:5060
                  auth_username: vox-customer-12
                  auth_password: <your-sip-password>
                  memo: 본사 대표번호
              ip_whitelist:
                summary: IP 화이트리스트 기반 SIP (인증 불필요)
                value:
                  number: '07011112222'
                  address: sip:203.0.113.42
                  memo: 지사 SIP gateway
        required: true
        description: custom SIP 전화번호 등록 요청입니다.
      responses:
        '201':
          description: 성공 응답
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TelephoneNumberResponse'
        '400':
          description: 요청 검증 오류
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                validationError:
                  summary: 요청 검증 오류
                  value:
                    error:
                      code: VALIDATION_ERROR
                      message: Request validation failed.
                      details:
                        field: name
                        reason: must not be blank
        '401':
          description: 인증이 필요합니다.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                unauthorized:
                  summary: Bearer 토큰 누락 또는 오류
                  value:
                    error:
                      code: UNAUTHORIZED
                      message: Authentication is required.
                      details: {}
        '403':
          description: 권한이 없습니다.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                forbidden:
                  summary: 권한이 없습니다.
                  value:
                    error:
                      code: FORBIDDEN
                      message: Permission denied.
                      details: {}
        '404':
          description: 리소스를 찾을 수 없습니다.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                notFound:
                  summary: 리소스를 찾을 수 없습니다.
                  value:
                    error:
                      code: RESOURCE_NOT_FOUND
                      message: Resource not found.
                      details:
                        resource: agent
        '409':
          description: 충돌이 발생했습니다.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                conflict:
                  summary: 상태 충돌이 발생했습니다.
                  value:
                    error:
                      code: CONFLICT
                      message: The requested operation conflicts with current state.
                      details:
                        current_status: draft
        '429':
          description: 요청 한도를 초과했습니다.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                rateLimited:
                  summary: 요청 한도를 초과했습니다.
                  value:
                    error:
                      code: RATE_LIMIT_EXCEEDED
                      message: Too many requests.
                      details:
                        limit: 5
                        window_seconds: 1
        '500':
          description: 서버 내부 오류가 발생했습니다.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                internalError:
                  summary: 서버 내부 오류가 발생했습니다.
                  value:
                    error:
                      code: INTERNAL_ERROR
                      message: Internal server error.
                      details: {}
        '503':
          description: 서비스를 일시적으로 사용할 수 없습니다.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                serviceUnavailable:
                  summary: 서비스를 일시적으로 사용할 수 없습니다.
                  value:
                    error:
                      code: SERVICE_UNAVAILABLE
                      message: Service temporarily unavailable.
                      details: {}
      security:
        - BearerAuth: []
components:
  schemas:
    RegisterNumberRequest:
      properties:
        number:
          type: string
          maxLength: 20
          minLength: 1
          pattern: ^\d+$
          title: Number
          description: 등록할 전화번호입니다. 하이픈 없이 입력합니다.
        address:
          type: string
          title: Address
          description: SIP trunk 연동에 사용할 SIP 주소입니다.
        auth_username:
          anyOf:
            - type: string
            - type: 'null'
          title: Auth Username
          description: SIP trunk 인증에 사용할 사용자명입니다.
        auth_password:
          anyOf:
            - type: string
            - type: 'null'
          title: Auth Password
          description: SIP trunk 인증에 사용할 비밀번호입니다.
        memo:
          anyOf:
            - type: string
              maxLength: 200
            - type: 'null'
          title: Memo
          description: 전화번호에 대한 메모입니다. 최대 200자.
      type: object
      required:
        - number
        - address
      title: RegisterNumberRequest
      description: >-
        custom SIP endpoint 등록 요청.


        에이전트 매핑은 등록 후 PATCH /{organization_telephone_number_id}/agent 로 별도
        설정합니다.
    TelephoneNumberResponse:
      properties:
        id:
          type: string
          title: Id
          description: 전화번호 레코드의 고유 식별자입니다.
        number:
          type: string
          title: Number
          description: 등록된 전화번호입니다. 하이픈 없는 숫자 문자열로 반환됩니다.
        provider:
          $ref: '#/components/schemas/TelephoneProvider'
          description: 번호 제공자 구분입니다. 'vox'(vox.ai 구매 번호) 또는 'custom'(자체 보유 번호) 중 하나입니다.
        monthly_fee:
          anyOf:
            - type: integer
            - type: 'null'
          title: Monthly Fee
          description: 월 사용료입니다. 단위는 원(KRW)이며, provider가 'custom'인 경우 null일 수 있습니다.
        status:
          $ref: '#/components/schemas/TelephoneStatus'
          description: >-
            번호의 현재 상태를 나타냅니다. 'active'(사용 중), 'scheduled'(예약됨),
            'cancel_requested'(해지 요청됨), 'expired'(만료됨) 중 하나입니다.
        address:
          anyOf:
            - type: string
            - type: 'null'
          title: Address
          description: SIP trunk 연동 주소입니다. SIP 설정이 없으면 null입니다.
        inbound_trunk_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Inbound Trunk Id
          description: 인바운드 SIP trunk의 고유 식별자입니다. SIP 설정이 없으면 null입니다.
        outbound_trunk_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Outbound Trunk Id
          description: 아웃바운드 SIP trunk의 고유 식별자입니다. SIP 설정이 없으면 null입니다.
        inbound_agent:
          anyOf:
            - $ref: '#/components/schemas/AgentMapping'
            - type: 'null'
          description: 이 번호에 매핑된 인바운드 에이전트 정보입니다. 매핑이 없으면 null입니다.
        outbound_agent:
          anyOf:
            - $ref: '#/components/schemas/AgentMapping'
            - type: 'null'
          description: 이 번호에 매핑된 아웃바운드 에이전트 정보입니다. 매핑이 없으면 null입니다.
        memo:
          anyOf:
            - type: string
            - type: 'null'
          title: Memo
          description: 전화번호에 대한 메모입니다. 설정되지 않았으면 null입니다.
        start_at:
          type: integer
          title: Start At
          description: 전화번호 서비스 시작일입니다. unix timestamp (ms).
        end_at:
          anyOf:
            - type: integer
            - type: 'null'
          title: End At
          description: 전화번호 서비스 종료일입니다. unix timestamp (ms). 해지 예약이 없으면 null입니다.
        cancel_requested_at:
          anyOf:
            - type: integer
            - type: 'null'
          title: Cancel Requested At
          description: 해지 요청이 접수된 일시입니다. unix timestamp (ms). 해지 요청이 없으면 null입니다.
        created_at:
          type: integer
          title: Created At
          description: 리소스 생성 시각입니다. unix milliseconds 형식입니다.
        updated_at:
          type: integer
          title: Updated At
          description: 리소스 마지막 수정 시각입니다. unix milliseconds 형식입니다.
      type: object
      required:
        - id
        - number
        - provider
        - status
        - start_at
        - created_at
        - updated_at
      title: TelephoneNumberResponse
      description: 조직 보유 전화번호 응답입니다.
    ErrorResponse:
      type: object
      required:
        - error
      title: ErrorResponse
      description: 모든 실패 응답에서 사용하는 v3 error envelope입니다.
      examples:
        - error:
            code: VALIDATION_ERROR
            message: Request validation failed.
            details:
              field: name
              reason: must not be blank
      properties:
        error:
          $ref: '#/components/schemas/ErrorDetail'
          description: 오류 payload입니다.
    TelephoneProvider:
      type: string
      enum:
        - vox
        - custom
      title: TelephoneProvider
      description: 번호 제공자 구분.
    TelephoneStatus:
      type: string
      enum:
        - active
        - scheduled
        - cancel_requested
        - expired
      title: TelephoneStatus
      description: 전화번호 lifecycle 상태입니다.
    AgentMapping:
      additionalProperties: false
      description: >-
        `agent_id`와 `agent_version` 매핑입니다.


        요청·응답 모두에서 에이전트 매핑이 필요한 경우 이 타입을 사용합니다. version 지정이 필요 없는 엔드포인트는 flat
        `agent_id: UUID`를 직접 받고 `AgentMapping`을 사용하지 않습니다.
      properties:
        agent_id:
          description: 에이전트 UUID입니다.
          format: uuid
          title: Agent Id
          type: string
        agent_version:
          default: current
          description: >-
            에이전트 버전입니다. 허용값은 "current", "production", "v{n}"(n≥1)입니다. 보내지 않으면
            "current"로 처리합니다. null 전송은 거부합니다.
          title: Agent Version
          type: string
          pattern: ^(current|production|v[1-9][0-9]*)$
          examples:
            - current
            - production
            - v1
      required:
        - agent_id
      title: AgentMapping
      type: object
    ErrorDetail:
      type: object
      required:
        - code
        - message
        - details
      title: ErrorDetail
      description: 기계가 읽을 수 있는 v3 오류 상세 정보입니다.
      examples:
        - code: VALIDATION_ERROR
          message: Request validation failed.
          details:
            field: name
            reason: must not be blank
      properties:
        code:
          type: string
          title: Code
          description: 기계가 읽을 수 있는 오류 code입니다. message parsing 대신 이 값을 사용합니다.
          examples:
            - VALIDATION_ERROR
        message:
          type: string
          title: Message
          description: 사용자에게 표시할 수 있는 오류 메시지입니다. 프로그램 처리는 `code`를 사용합니다.
          examples:
            - Request validation failed.
        details:
          type: object
          title: Details
          additionalProperties: true
          description: 구조화된 context입니다. 주로 `field`, `reason`, `allowed_values`를 포함합니다.
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: Organization API key
      description: '조직 API 키를 `Authorization: Bearer <token>` 형식으로 보냅니다.'

````