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

# 문자 발신

> 문자 발신이 켜진 워크스페이스 전화번호로 SMS, LMS, MMS를 발신합니다. 이미지는 파일 업로드 API가 돌려준 파일 키를 `image_file_keys`로 넘겨 첨부합니다.



## OpenAPI

````yaml /api-reference/v3/openapi.json post /sms
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:
  /sms:
    post:
      tags:
        - SMS
      summary: 문자 발신
      description: >-
        문자 발신이 켜진 워크스페이스 전화번호로 SMS, LMS, MMS를 발신합니다. 이미지는 파일 업로드 API가 돌려준 파일 키를
        `image_file_keys`로 넘겨 첨부합니다.
      operationId: sendSms
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            description: >-
              같은 POST 요청을 24시간 동안 안전하게 재시도하기 위한 선택적 멱등성 키입니다. 지정할 경우 비어 있으면 안 되며
              최대 255자까지 허용합니다.
            title: Idempotency-Key
          description: >-
            같은 POST 요청을 24시간 동안 안전하게 재시도하기 위한 선택적 멱등성 키입니다. 지정할 경우 비어 있으면 안 되며
            최대 255자까지 허용합니다.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SMSSendRequest'
            examples:
              sms:
                summary: SMS
                value:
                  from_number: '07011112222'
                  to_number: '01012345678'
                  message: 예약 확인 안내드립니다.
                  metadata:
                    external_id: sms_20260526_001
              lms:
                summary: LMS
                value:
                  from_number: '07011112222'
                  to_number: '01012345678'
                  title: 예약 안내
                  message: 예약 확인 안내드립니다. 방문 전 안내사항을 확인해 주세요.
              mms:
                summary: MMS
                value:
                  from_number: '07011112222'
                  to_number: '01012345678'
                  title: 이미지 안내
                  message: 첨부 이미지를 확인해 주세요.
                  image_file_keys:
                    - file_abc123
                    - file_def456
        description: >-
          문자 발신 요청 본문입니다. 텍스트만 보내는 SMS/LMS는 `image_file_keys`를 생략하고, MMS는 파일 키를
          최대 3개까지 넣습니다.
      responses:
        '201':
          description: 성공 응답
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SMSSendResponse'
              example:
                id: a1b2c3d4e5f6
                from_number: '07011112222'
                to_number: '01012345678'
                message: 예약 확인 안내드립니다.
                message_type: sms
                byte_count: 23
                metadata:
                  external_id: sms_20260526_001
                status: queued
                created_at: 1793051400000
        '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:
                idempotencyKeyConflict:
                  summary: 다른 요청에 다시 쓴 Idempotency-Key
                  value:
                    error:
                      code: IDEMPOTENCY_KEY_CONFLICT
                      message: 동일한 Idempotency-Key가 다른 요청 또는 실행 주체에 사용되었습니다.
                      details:
                        idempotency_key: sms-20260526-001
                idempotencyKeyInProgress:
                  summary: 같은 Idempotency-Key의 요청을 처리하는 중
                  value:
                    error:
                      code: IDEMPOTENCY_KEY_IN_PROGRESS
                      message: 이 Idempotency-Key는 현재 처리 중입니다. 잠시 후 다시 시도해 주세요.
                      details:
                        idempotency_key: sms-20260526-001
        '429':
          description: >-
            요청 한도를 초과했습니다. API 키 트래픽은 기본값으로 워크스페이스당 초당 5회·분당 120회, Supabase JWT
            트래픽은 기본값으로 사용자당 초당 10회·분당 240회로 제한되며, 워크스페이스 대시보드에는 기본 분당 2,400회의
            백스톱 한도가 적용됩니다. 한도는 운영자가 조정할 수 있고, 초과한 버킷의 실제 한도와 윈도우는 429 응답의
            X-RateLimit-Limit·X-RateLimit-Window 헤더로 알려 줍니다. 개별 경로 자체 리미터가 만든
            429 응답에는 이 헤더가 없을 수 있습니다.
          headers:
            Retry-After:
              description: >-
                초과한 공용 v3 인증 주체(auth-principal) 리미터 윈도우가 초기화될 때까지 남은 시간입니다. 단위는
                초입니다. 개별 경로 자체 리미터가 만든 429 응답에는 이 헤더가 없을 수 있습니다.
              schema:
                type: integer
                minimum: 1
            X-RateLimit-Limit:
              description: >-
                초과한 공용 v3 인증 주체(auth-principal) 리미터 윈도우의 최대 요청 수입니다. 개별 경로 자체
                리미터가 만든 429 응답에는 이 헤더가 없을 수 있습니다.
              schema:
                type: integer
                minimum: 1
            X-RateLimit-Window:
              description: >-
                초과한 공용 v3 인증 주체(auth-principal) 리미터 윈도우의 길이입니다. 단위는 초입니다. 개별 경로
                자체 리미터가 만든 429 응답에는 이 헤더가 없을 수 있습니다.
              schema:
                type: integer
                minimum: 1
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                rateLimited:
                  summary: 요청 한도를 초과했습니다.
                  value:
                    error:
                      code: RATE_LIMIT_EXCEEDED
                      message: Too many requests.
                      details:
                        limit: 10
                        window_seconds: 1
                        scope: user
        '500':
          description: >-
            서버 오류입니다. `SMS_RESULT_UNKNOWN`이면 통신사가 문자를 접수했을 수 있으니 자동으로 다시 보내거나 새
            `Idempotency-Key`로 재시도하지 마세요. `status`가 `failed`여도 접수되지 않았다는 뜻은
            아닙니다. `error.details.sms_message_id`의 문자를 조회해 확인하고, 필요하면 지원팀에 문의해
            주세요. 그 밖의 서버 오류는 `INTERNAL_ERROR`입니다.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                internalError:
                  summary: 서버 내부 오류가 발생했습니다.
                  value:
                    error:
                      code: INTERNAL_ERROR
                      message: Internal server error.
                      details: {}
                smsResultUnknown:
                  summary: 문자 접수 여부를 알 수 없음, 자동으로 다시 보내지 않음
                  value:
                    error:
                      code: SMS_RESULT_UNKNOWN
                      message: 문자 발신 결과를 확인할 수 없습니다.
                      details:
                        sms_message_id: a1b2c3d4e5f6
                        user_key: a1b2c3d4e5f6
        '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:
    SMSSendRequest:
      properties:
        from_number:
          type: string
          title: From Number
          description: 발신번호입니다. 인증된 워크스페이스가 소유하고 문자 발신이 켜진 번호여야 합니다. 하이픈 없는 국내 번호입니다.
          examples:
            - '07011112222'
        to_number:
          type: string
          title: To Number
          description: '수신번호입니다. 하이픈 없는 국내 번호입니다(예: ''01012345678'').'
          examples:
            - '01012345678'
        message:
          type: string
          title: Message
          description: >-
            문자 본문입니다. EUC-KR 기준 90바이트 이하이고 제목과 이미지가 없으면 SMS, 90바이트를 넘기거나 제목이 있으면
            LMS, 이미지를 첨부하면 MMS로 발신됩니다. 본문과 제목에 EUC-KR로 표현할 수 없는 문자(예: 이모지)가 있으면
            SMS_UNSUPPORTED_CHARSET(400)으로 거절됩니다.
          examples:
            - 예약 확인 안내드립니다.
        title:
          anyOf:
            - type: string
            - type: 'null'
          title: Title
          description: 선택 제목입니다. 지정하면 LMS 또는 MMS로 발신됩니다.
          examples:
            - 예약 안내
        image_file_keys:
          anyOf:
            - items:
                type: string
              type: array
              maxItems: 3
            - type: 'null'
          title: Image File Keys
          description: >-
            이미지 첨부 파일 키입니다. 파일 업로드 API에 purpose=sms_attachment로 올린 파일의
            file_key이며 최대 3개까지 지정할 수 있습니다. 업로드 규격은 JPEG·PNG·WebP는 원본 2MB
            이하(JPEG로 변환한 결과 1MB 이하), GIF는 2MB 이하입니다. 텍스트만 보내면 생략하거나 null 또는 빈
            배열을 전달합니다.
          examples:
            - - file_abc123
              - file_def456
        call_id:
          anyOf:
            - type: string
              format: uuid
            - type: 'null'
          title: Call Id
          description: >-
            이 문자를 귀속시킬 통화 UUID입니다. 인증된 워크스페이스가 소유한 통화여야 하며, 존재하지 않거나 다른 워크스페이스의
            통화이면 발신 없이 거절됩니다. 통화와 무관한 발신이면 생략합니다.
          examples:
            - 3f2504e0-4f89-11d3-9a0c-0305e82c3301
        metadata:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          title: Metadata
          description: 요청과 대응시키기 위한 선택 메타데이터입니다. 조회 응답과 sms_sent webhook에 그대로 포함됩니다.
          examples:
            - external_id: sms_20260526_001
        reseller_code:
          anyOf:
            - type: string
              pattern: ^\d{9}$
            - type: 'null'
          title: Reseller Code
          description: >-
            특수유형 부가통신사업자 식별코드입니다(숫자 9자리). 문자중계·재판매사업자가 아니면 생략합니다. 허용된 워크스페이스에서만
            전송됩니다.
      additionalProperties: false
      type: object
      required:
        - from_number
        - to_number
        - message
      title: SMSSendRequest
      description: '`POST /v3/sms` 요청 본문입니다.'
    SMSSendResponse:
      properties:
        id:
          type: string
          pattern: ^[0-9a-f]{12}$
          title: Id
          description: 문자의 고유 식별자입니다.
          examples:
            - a1b2c3d4e5f6
        from_number:
          type: string
          title: From Number
          description: 발신번호입니다.
          examples:
            - '07011112222'
        to_number:
          anyOf:
            - type: string
            - type: 'null'
          title: To Number
          description: 수신번호입니다. 보존 기간이 지나 지운 번호는 null입니다.
          examples:
            - '01012345678'
        message:
          type: string
          title: Message
          description: 수신자에게 발신한 문자 본문입니다.
          examples:
            - 예약 확인 안내드립니다.
        title:
          anyOf:
            - type: string
            - type: 'null'
          title: Title
          description: 문자 제목입니다. 없으면 null입니다.
        message_type:
          type: string
          enum:
            - sms
            - lms
            - mms
          title: Message Type
          description: 확정된 문자 유형입니다('sms', 'lms', 'mms').
        byte_count:
          type: integer
          minimum: 0
          title: Byte Count
          description: >-
            문자를 만들 때 계산해 저장한 바이트 수입니다. 신규 발신은 EUC-KR 기준이며 이전 기록은 당시 저장된 값을
            반환합니다.
          examples:
            - 23
        image_urls:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          title: Image Urls
          description: MMS에 첨부한 이미지 URL입니다. 텍스트만 보낸 발신이면 null입니다.
        call_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Call Id
          description: >-
            귀속된 통화 UUID입니다. 통화 중 에이전트의 send_sms 툴로 발신했거나 발신 요청이 call_id를 지정한 경우
            채워지며, 통화에 귀속되지 않으면 null입니다.
        chat_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Chat Id
          description: >-
            귀속된 채팅 UUID입니다. 문자 채팅의 에이전트 답변이나 outbound 메시지로 발신한 경우 채워지며, 채팅에 귀속되지
            않으면 null입니다.
        customer_id:
          anyOf:
            - type: string
              format: uuid
            - type: 'null'
          title: Customer Id
          description: 서버가 상대방 전화번호로 귀속한 고객 UUID입니다. 아직 고객 귀속이 완료되지 않았으면 null입니다.
        metadata:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          title: Metadata
          description: 발신 요청에 담아 보낸 메타데이터입니다. 없으면 null입니다.
          examples:
            - external_id: sms_20260526_001
        batch_id:
          anyOf:
            - type: string
              format: uuid
            - type: 'null'
          title: Batch Id
          description: 이 문자가 속한 대량 문자 발신의 UUID입니다. 대량 문자 발신으로 보내지 않은 문자는 null입니다.
        status:
          $ref: '#/components/schemas/SMSDeliveryStatus'
          description: >-
            발신 상태입니다. pending은 발신 처리 중, queued는 통신사 최종 결과를 기다리는 상태로 아직 요금이 부과되지
            않으며, 결과는 보통 몇 초 안에 정해지지만 수신 휴대폰이 꺼져 있으면 최대 24시간이 걸립니다. sent는 요금이
            부과되는 성공이며 단말 수신이나 열람을 보장하지 않습니다. failed는 발신 실패, blocked는 제한된 내용이
            포함되어 발신하지 않은 상태, canceled는 대량 문자 발신이 취소되어 발신하지 않은 상태입니다. legacy는 발신
            상태를 기록하기 전의 과거 기록입니다.
        error:
          anyOf:
            - $ref: '#/components/schemas/SMSMessageError'
            - type: 'null'
          description: failed, blocked, canceled 상태일 때의 사유입니다. 그 외 상태에서는 null입니다.
        created_at:
          type: integer
          title: Created At
          description: 리소스 생성 시각입니다. unix milliseconds 형식입니다.
          examples:
            - 1793051400000
        delivered_at:
          anyOf:
            - type: integer
            - type: 'null'
          title: Delivered At
          description: >-
            문자가 수신 휴대폰에 전달된 시각입니다(unix ms). sent 상태일 때만 채워지며, 전달되지 않았거나 전달 시각을 알
            수 없으면 null입니다.
      type: object
      required:
        - id
        - from_number
        - to_number
        - message
        - message_type
        - byte_count
        - status
        - created_at
      title: SMSSendResponse
      description: v3 발신 문자 리소스 페이로드입니다.
      examples:
        - byte_count: 23
          created_at: 1793051400000
          from_number: '07011112222'
          id: a1b2c3d4e5f6
          message: 예약 확인 안내드립니다.
          message_type: sms
          metadata:
            external_id: sms_20260526_001
          status: queued
          to_number: '01012345678'
    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입니다.
    SMSDeliveryStatus:
      type: string
      enum:
        - pending
        - queued
        - sent
        - failed
        - blocked
        - canceled
        - legacy
      title: SMSDeliveryStatus
      description: |-
        발신 상태입니다. pending은 발신 처리 중, queued는 통신사 최종 결과를 기다리는 상태(아직 요금 부과 전),
        sent는 요금이 부과되는 성공, failed는 발신 실패, blocked는 제한된 내용이 포함되어 발신하지 않은 상태,
        canceled는 대량 문자 발신 취소로 발신하지 않은 상태, legacy는 발신 상태를 기록하기 전의 과거 기록입니다.
    SMSMessageError:
      properties:
        code:
          type: string
          title: Code
          description: >-
            기계 판독용 오류 코드입니다. failed일 때, 통신사 결과로 실패했으면 SMS_INVALID_RECIPIENT(없거나
            사용이 정지된 번호), SMS_RECIPIENT_UNREACHABLE(수신 휴대폰이 꺼져 있거나 받을 수 없는 상태),
            SMS_SPAM_BLOCKED(통신사 스팸 차단), SMS_SENDER_NUMBER_REJECTED(발신번호가 통신사
            기준에 맞지 않음), SMS_DELIVERY_UNCONFIRMED(전달 여부 확인 불가),
            SMS_NO_RESULT(24시간 안에 결과를 받지 못함) 중 하나입니다. 발신 전에 요청 검증에서 실패했으면 그 검증
            코드(예: 첨부 파일을 찾을 수 없을 때 FILE_NOT_FOUND)이고, 구체적인 사유가 없으면
            SMS_SEND_FAILED입니다. blocked일 때는 SMS_CONTENT_BLOCKED(제한된 내용 포함),
            BILLING_SUSPENDED(미납으로 인한 발신 정지), BLOCKED_NUMBER(광고 문자 수신 거부 번호),
            SMS_BLOCKED(그 밖의 발신 제한)입니다. canceled일 때는 SMS_CANCELED입니다.
          examples:
            - SMS_SEND_FAILED
        message:
          type: string
          title: Message
          description: 사람이 읽는 사유입니다.
          examples:
            - 문자 발신에 실패했습니다.
      type: object
      required:
        - code
        - message
      title: SMSMessageError
      description: 발신 문자가 failed, blocked, canceled 인 사유.
    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>` 형식으로 보냅니다.'

````

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